<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Point of Indifference]]></title><description><![CDATA[Rational risk management in cybersecurity]]></description><link>https://lapitsky.com/</link><image><url>https://lapitsky.com/favicon.png</url><title>Point of Indifference</title><link>https://lapitsky.com/</link></image><generator>Ghost 6.6</generator><lastBuildDate>Mon, 08 Jun 2026 17:47:24 GMT</lastBuildDate><atom:link href="https://lapitsky.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Hardware wallets for your company]]></title><description><![CDATA[Simple guide for bootstrapping your business on-chain]]></description><link>https://lapitsky.com/hardware-wallets/</link><guid isPermaLink="false">65a2056303e6440001f7fbbc</guid><category><![CDATA[Security]]></category><category><![CDATA[Blockchain]]></category><dc:creator><![CDATA[Alexey Lapitsky]]></dc:creator><pubDate>Sat, 13 Jan 2024 04:08:26 GMT</pubDate><content:encoded><![CDATA[<p> </p>
<p>This simple guide is intended for companies just bootstrapping their blockchain presence. If your business needs a workflow for minting tokens or operating smart contracts as a corporate entity using multisigs and you just purchased a few Ledgers for that, this guide shines some light on how to use hardware wallets in a safe way.</p>
<h2 id="core-concepts">Core concepts</h2>
<p>To sign transactions on most blockchain networks you need a <strong>private key</strong>. You can think of it as a file with secret data. If your private key is stolen, your identity is compromised and there is no way to recover from it: an attacker can impersonate you and sign transactions as if they were you.</p>
<p>A <strong>seed phrase</strong> is a sequence of words which are used to derive a private key. Stealing a seed phrase is the same as stealing a private key.</p>
<p><strong>Hardware wallets</strong> are designed to make your private keys and seed phrases hard to steal by storing them on a separate device (instead of your laptop/pc which could be easily hacked).</p>
<h2 id="rule-1-dont-enter-your-seed-phrase-anywhere">Rule #1: Don&apos;t enter your seed phrase anywhere</h2>
<p>During onboarding, your hardware wallet will generate a random sequence of 24 words, displaying one at a time on the device&apos;s screen &#x2014; this is what is called a seed phrase. Write those words down on paper and put it in a deposit box in your bank.</p>
<p>Under no circumstances should you share the seed phrase with anybody. That includes typing these words anywhere, including your own laptop or your phone.</p>
<h2 id="rule-2-use-your-wallet-only-for-multisigs">Rule #2: Use your wallet only for multisigs</h2>
<p>Your wallet will be used for signing multisig transactions only. Do not store any funds on your wallet and do not use it for any personal activities.</p>
<p>Attackers will try to trick you into signing malicious transactions and it will not be possible to distinguish when it happens. To use most multisigs you will have to enable Blind signing so it will be impossible to validate what you are signing on the display of your wallet.</p>
<p>Connect your wallet only to the multisig website and nothing else.</p>
<h2 id="rule-3-keep-identities-private">Rule #3: Keep identities private</h2>
<p>The address of your wallet is usually not considered to be private but it is important that your identity and the identities of other participants of multisigs are not disclosed.</p>
<p>If attackers know who the addresses belong to it makes it much easier to target these individuals with spear phishing. Protecting your identities will also minimise risks of targeted physical attacks and many other risks.</p>
<p></p>
<p>This is far from the exhaustive list of best practices but it is a good foundation keep you going. Read more about <a href="https://lapitsky.com/dont-trust/" rel="noreferrer">protecting yourself on-chain</a> and keep an eye out for more posts!</p>]]></content:encoded></item><item><title><![CDATA[Don't trust – verify]]></title><description><![CDATA[Protect yourself against the recent Ledger attack]]></description><link>https://lapitsky.com/dont-trust/</link><guid isPermaLink="false">657b5e520b1e10000113c65a</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Security]]></category><category><![CDATA[Tech]]></category><category><![CDATA[News]]></category><dc:creator><![CDATA[Alexey Lapitsky]]></dc:creator><pubDate>Thu, 14 Dec 2023 20:30:47 GMT</pubDate><content:encoded><![CDATA[<p>Blockchain is designed to be trustless. Ironically, in crypto, you must assume that everyone is trying to lie and steal from you.</p>
<p>Even if you are not doing anything out of the ordinary, even your priceless meme coins could still be drained, like in the recent ~500m <a href="https://www.coindesk.com/business/2023/12/14/ledger-exploit-drained-484k-upended-defi-former-staffer-linked-to-malicious-code/?ref=lapitsky.com" rel="noreferrer">ledger attack</a>.</p>
<p>Here are a couple of quick tips on how to reduce such risks.</p>
<h2 id="separate-your-accounts">Separate your accounts </h2>
<p>Most of your funds must be stored on a separate, dedicated address in a hardware wallet that is not used for your daily activities. Your hardware wallet can derive multiple accounts from a single seed phrase and splitting your daily account from your savings account this way will limit the impact of a compromise.</p>
<p>If you want to go further, set up an additional account derived from 13th or 25th word pass phrase, hidden behind a separate pin code.</p>
<h2 id="assume-malicious-destination">Assume malicious destination</h2>
<p>Always add the recipient addresses to your address book first and never copy or type these addresses again.</p>
<p>Attackers will try to fool you by generating malicious addresses matching most of the letters in the expected address so you must compare every single letter when adding new addresses to your address book.</p>
<p>You will see malicious addresses in the list of your past transactions, in your emails, messengers and your social media &#x2013; don&apos;t trust anything not in your address book.</p>
<p>Always check the display of your hardware wallet when signing transactions &#x2013; read and compare the destination address diligently.</p>
<p></p>
<p>Stay safe out there!</p>]]></content:encoded></item><item><title><![CDATA[How to get paid $800k for a Clippy warning]]></title><description><![CDATA[Retrospective on a critical bridge vulnerability that was detectable by a linter]]></description><link>https://lapitsky.com/how-to-get-paid-800k-for-a-clippy-warning/</link><guid isPermaLink="false">655569a425cec3000144a581</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Security]]></category><category><![CDATA[Tech]]></category><dc:creator><![CDATA[Alexey Lapitsky]]></dc:creator><pubDate>Thu, 16 Nov 2023 01:03:46 GMT</pubDate><content:encoded><![CDATA[<p></p>
<p>The largest bug bounty reward paid by <a href="https://aurora.dev/?ref=lapitsky.com" rel="noreferrer">Aurora</a> last year was $800k, which is a big step down from $6m the year before. This post is a public retrospective and my thoughts on how to prevent similar bugs in the future.</p>
<h1 id="what-was-the-bug-about">What was the bug about</h1>
<p><a href="https://rainbowbridge.app/?ref=lapitsky.com" rel="noreferrer">Rainbow Bridge</a> allows sending tokens across blockchain networks by locking assets in a custodian contract on one chain, and minting new tokens on another.</p>
<p>The bug was in a component that is responsible for minting on the <a href="https://near.org/?ref=lapitsky.com" rel="noreferrer">NEAR</a> side. It allowed an attacker to drain all tokens from the custodian contract &#x2013; one of the most critical bugs that could have devastated the entire NEAR ecosystem.</p>
<p>The core of the issue was in the <code>log_index</code> sent with the bridging &#x201C;proof&#x201D;:</p>
<pre><code class="language-Rust">#[serializer(borsh)] log_index: u64;</code></pre>
<p>That value was converted to <code>usize</code> by the recipient contract, which is normally not a problem as it matches <code>u64</code>:</p>
<pre><code class="language-Rust">assert_eq!(receipt.logs[log_index as usize], log_entry);</code></pre>
<p>However, on NEAR, the Rust code is compiled to wasm32 and as result the <code>log_index</code> is truncated. &#xA0;By re-using the &quot;proof&quot; with a modified <code>log_index</code> value an attacker could mint tokens 2**32 times and drain all the assets in the custodian contract.</p>
<p>As simple as that!</p>
<h1 id="why-it-happened">Why it happened</h1>
<p>We were well aware about wasm32 but the <a href="https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/as_conversions.rs?ref=lapitsky.com"><u>as_conversions</u></a> Clippy check was not enabled for the affected component in the repository &#x2013; our linter setup failed us. Our defensive programming practices were not good enough.  The problem also wasn&#x2019;t caught by internal reviews nor by multiple big-name auditors.&#xA0;</p>
<p>Security is a cake and it&#x2019;s absolutely required to have many layers! Stay humble and expect that any single measure could fail.</p>
<p>I promise to talk more about cakes later, but today I would like to say a couple of words about Clippy.&#xA0;</p>
<h1 id="rust-linting-tips">Rust linting tips</h1>
<p>Here is the bare minimum you have to do for setting up Clippy for security-sensitive applications:</p>
<ul><li>Explicitly enable all Clippy lints. Yes, you must enable all of them: for example, <code>as_conversions</code> are not included even in the <code>pedantic</code> group.</li><li>Keep track of every single Rust component in your monorepos and make sure that Clippy configuration is consistent everywhere and that linter checks are actually executed in the CI.</li><li>Make sure that Clippy config in the local development environments matches security CI workflows</li></ul>
<p>While it may sound like a lot of work to address every single Clippy warning, it&#x2019;s fast and simple compared to the rest of the security measures typically required &#x2013; just don&#x2019;t overlook the basics.</p>
<p>Hope these simple tips could prevent a hack of a decentralized bridge or two.</p>
<p> Kudos to Goohong Jung (cybermong) for responsibly disclosing the vulnerability and taking a well deserved place in our hall of fame.</p>]]></content:encoded></item><item><title><![CDATA[On bug bounty effectiveness]]></title><description><![CDATA[Smart contract changes do not get enough scrutiny from bounty hunters — here’s how you can change that.]]></description><link>https://lapitsky.com/bug-bounty-effectiveness/</link><guid isPermaLink="false">6517ea2b25cec3000144a2ee</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Security]]></category><category><![CDATA[Tech]]></category><dc:creator><![CDATA[Alexey Lapitsky]]></dc:creator><pubDate>Sat, 30 Sep 2023 17:56:11 GMT</pubDate><content:encoded><![CDATA[<p>At <a href="https://aurora.dev/?ref=lapitsky.com" rel="noreferrer">Aurora</a>, we have an impressive track record of running bug bounties that includes rewarding a whitehat with the <a href="https://cointelegraph.com/news/aurora-pays-6m-bug-bounty-to-ethical-security-hacker-through-immunefi?ref=lapitsky.com" rel="noreferrer">second largest bounty</a> in the history of crypto (so far!). One unique aspect of our bounty program is that we have a pretty large scope so many problems become visible at our scale.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://lapitsky.com/content/images/2023/10/bounties.png" class="kg-image" alt="Bounties paid by Aurora in the last 2 years" loading="lazy" width="692" height="349" srcset="https://lapitsky.com/content/images/size/w600/2023/10/bounties.png 600w, https://lapitsky.com/content/images/2023/10/bounties.png 692w"><figcaption><span style="white-space: pre-wrap;">Bounties paid by Aurora in the last 2 years</span></figcaption></figure>
<p>The burden of on-chain change tracking is a main contributor to why bug bounty effectiveness declines over time. Below I explain why that is and my thoughts on how we can solve this.</p>
<h2 id="false-sense-of-security">False sense of security</h2>
<p>The first months after launching bounties are the most impactful (and stressful!) We&apos;ve paid most of the rewards within 3 months after including new contracts in scope of our bug bounty programs.</p>
<p>The initial smart contract launch often comes with a press release so bounty hunters rush to find low-hanging fruit missed by auditors. After some time the likelihood that &quot;many eyes&quot; have missed something declines, the whitehats switch to easier targets and, naturally, the quantity of bug reports decreases.</p>
<p>Unfortunately, there is no proportional influx of bug reports when major new features are released.</p>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">Major smart contract changes do not get the same level of scrutiny from whitehats.</div></div>
<p>The bounty scope does not explicitly change and whitehats need to continuously keep track of significant changes in the smart contracts to assess the likelihood of new bugs being introduced &#x2013; a much harder task to do.</p>
<h2 id="in-search-of-a-solution">In search of a solution</h2>
<p>There must be no ambiguity when new risky features get shipped to the contracts that are already covered by the bounty program so that bug hunters can focus on what they do best &#x2013; finding bugs, not keeping up with release schedules.</p>
<p>To do that we must reduce information asymmetry between the protocol developers and the whitehats as much as possible and introduce new incentives to bring bug bounty effectiveness back to the initial level:</p>
<ul><li>Announce significant changes for the contracts that are already in-scope</li><li>Allow whitehats to claim rewards before these features hit the mainnet</li><li>Provide an additional incentive for whitehats to audit such changes in a timely manner </li></ul>
<p>Ideally, bug bounty platforms could have a feed of upcoming changes to the contracts that are already in scope, describing what has changed and incentivising researchers to audit them before a certain deadline. Unfortunately, most of the platforms do not provide these capabilities yet. </p>
<p>When it comes to Aurora, we are working with our partners on integrating the practice of audit contests directly into the bug bounty programs to address exactly this problem. The main difference from continuously running bounty programs is that such contests will be relatively short to provide time-sensitive feedback and will cover bugs that are normally out-of-scope e.g. non-production code that is behind feature flags, best practices and performance issues that could hint at security problems.</p>
<p>In conclusion, I firmly believe that alleviating the burden of change tracking from whitehats will significantly enhance the effectiveness of bug bounty programs, contributing to a more secure ecosystem. Stay tuned for insights and lessons learned as we roll out upcoming contests!</p>]]></content:encoded></item><item><title><![CDATA[Practical ERC20 burning]]></title><description><![CDATA[Do not use contract burns, use well-known burn addresses.]]></description><link>https://lapitsky.com/erc20-burning/</link><guid isPermaLink="false">6506aa2833c7640001d5e282</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Tech]]></category><dc:creator><![CDATA[Alexey Lapitsky]]></dc:creator><pubDate>Sun, 17 Sep 2023 14:22:41 GMT</pubDate><content:encoded><![CDATA[<p>Token burning is the act of permanently removing a certain number of tokens from circulation. This article delves into its intricacies and offers guidance based on my real-world experiences at <a href="https://aurora.dev/?ref=lapitsky.com">Aurora</a>.</p>
<h2 id="why-is-there-a-problem">Why is there a problem?</h2>
<p>The ERC20 standard does not inherently specify a token burning mechanism.</p>
<p>The most common implementation of ERC20, <a href="https://docs.openzeppelin.com/contracts/4.x/api/token/erc20?ref=lapitsky.com#ERC20Burnable">provides</a> <code>ERC20Burnable</code> to solve that, but not all deployed OpenZepellin contracts include <code>ERC20Burnable</code>. Many ERC20 contracts are locked and not upgradeable.</p>
<p>Due to these constraints, projects seek alternative ways to approach token burns.</p>
<h2 id="do-not-use-contract-burns">Do not use contract burns</h2>
<p>One often recommended way to burn tokens involves creating a contract which immediately self destructs and sends tokens to its own address. However, this method comes with its set of challenges:</p>
<ul><li>Overhead of creating, deploying and testing such contract, especially if the burn needs to happen periodically</li><li>Even if the contract uses <code>SELFDESTRUCT</code> it does not preclude the possibility of redeploying another contract at the same address. This has been successfully exploited in the infamous <a href="https://forum.tornado.ws/t/full-governance-attack-description/62?ref=lapitsky.com">Tornado Cash attack</a> by using a metamorphic contract factory.</li><li>There is a negative sentiment against <code>SELFDESTRUCT</code> opcode and (although stagnant) <a href="https://eips.ethereum.org/EIPS/eip-4758?ref=lapitsky.com">EIP-4758</a> that highlights some security concerns.</li><li>Token burns via this method aren&apos;t recognised on most analytics platforms.</li></ul>
<p>Given the listed concerns, I advise against this approach and encourage the use of burn addresses.</p>
<h2 id="use-well-known-burn-addresses">Use well-known burn addresses</h2>
<p>A burn address is a recognized externally owned account (<a href="https://ethereum.org/en/whitepaper/?ref=lapitsky.com#ethereum-accounts">EOA</a>) where tokens can be sent to symbolize their destruction. While the token count remains unchanged, these tokens are effectively removed from circulation since no private key can control the burn address.</p>
<p>One of the common questions is &quot;what if somebody knows or brute forces the private keys for such EOA addresses?&quot;</p>
<p>Ethereum security model rests on the practical impossibility of brute forcing EOA accounts, so it does not make sense to take the risk of such attack into account when planning the burns. And to mitigate the risk of malicious burn addresses, use only the well-known ones.</p>
<p>You can find the list of burn addresses on <a href="https://etherscan.io/accounts/label/burn?ref=lapitsky.com">Etherscan</a> but I recommend limiting it to the top two that stand out by the TVL and number of transactions: <code>0x0000000000000000000000000000000000000000</code> (<em>null</em>) and <code>0x000000000000000000000000000000000000dEaD</code> (<em>dead</em>).</p>
<p>Interestingly, OpenZeppelin&apos;s ERC20 implementation restricts transfers to <em>null</em> which could leave you with the second best choice: <em>dead.</em></p>
<p>The benefit of using well-known burn addresses over &quot;contract burns&quot; is that burn addresses are accounted for and integrated into numerous analytics tools, ensuring accurate token burn data representation.</p>
<h2 id="bonus-tips">Bonus tips</h2>
<ul><li>Ensure that your ERC20 contract is locked and immutable before initiating burns.</li><li>For ERC20 tokens on multiple networks, execute burns on your primary network only, for unified tracking and analytics.</li><li>For the first burn, refrain from using decentralised or ZK-bridges. If your contract unexpectedly rejects the transaction (like disallowing transfers to <em>null</em>) &#x2013; it might muddle your analytics even though the tokens are technically burned.</li></ul>
<p>Big thanks to <a href="https://www.linkedin.com/in/lance-henderson/?ref=lapitsky.com">Lance Henderson</a> for technical insights and for reviewing this post!</p>]]></content:encoded></item><item><title><![CDATA[Nix for the Fence Sitters]]></title><description><![CDATA[Steps to integrate Nix into your personal setup.]]></description><link>https://lapitsky.com/nix/</link><guid isPermaLink="false">64fe23f20e693b00017f56a7</guid><category><![CDATA[Tech]]></category><dc:creator><![CDATA[Alexey Lapitsky]]></dc:creator><pubDate>Sat, 16 Sep 2023 17:21:00 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://nixos.org/?ref=lapitsky.com">Nix</a> is by far the best way (so far) of package and dev environment managers compared to anything else out there. Especially from the security perspective.</p>
<p>Assuming that you know what Nix is and what problems it solves, I will skip the what and why parts &#x2013; plenty of posts written on it already.</p>
<p>Nix is complex and once in a while people ask me if they should start using it for their personal environments and how much effort it would require. </p>
<p>The Nix learning curve varies from person to person and potential productivity gains depend on many factors. This post is my take on how you should approach this decision.</p>
<h2 id="just-because-you-can">Just because you can...</h2>
<p>Does it mean you should just migrate your workstation to NixOS / <a href="https://github.com/LnL7/nix-darwin?ref=lapitsky.com">nix-darwin</a>?</p>
<p>Not right away. If you are a programmer, try adopting <a href="https://github.com/numtide/devshell?ref=lapitsky.com">devshell</a> and <a href="https://zero-to-nix.com/concepts/flakes?ref=lapitsky.com">flakes</a> for a  project you are working on. You won&apos;t need to learn the Nix language in the beginning to rip the benefits and progressively expand your knowledge. This low-barrier experiment would allow you to form an opinion and would be a good signal to invest more time into it or not.</p>
<p>If you have worked with any functional language before and if you have a reasonable knowledge of Linux the odds are high that Nix would be a very good fit for you. Regardless, my advice does not change &#x2013; experiment with an isolated project first to learn and get familiar with Nix.</p>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">Step 1: Manage dependencies with flakes for one of your projects</div></div>
<p>If you want to go an extra mile with this experiment, you can try packaging your software using Nix as well and even possibly integrating it into a CI/CD pipeline. If it was too easy, you can also try using <a href="https://ryantm.github.io/nixpkgs/builders/images/dockertools/?ref=lapitsky.com">dockerTools</a> to build container images.</p>
<p>Avoid packaging TS/Javascript projects unless everything feels easy and straightforward already.</p>
<h2 id="if-you-decide-to-continue">If you decide to continue</h2>
<p>Then you can create a Nix repository for declarative configuration of your workstation(s).</p>
<p>If you are using macOS, you can start progressively replacing most of the Homebrew dependencies and OS settings with a combination of <code>nix-darwin</code> and project-local flakes.</p>
<p>If you are using Linux, you might consider switching to NixOS as well, but you&apos;d need more time on the reinstall. NixOS these days has a graphical installer based on <a href="https://calamares.io/?ref=lapitsky.com">https://calamares.io</a> which supports disk encryption out of the box. I personally use <a href="https://github.com/numtide/nixos-anywhere?ref=lapitsky.com">nix-anywhere</a> + <a href="https://github.com/nix-community/disko?ref=lapitsky.com">disko</a> with LUKS to install things remotely though. </p>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">Step 2: NixOS/nix-darwin monorepo for your workstation(s) </div></div>
<p> At this point you <a href="https://repology.org/repositories/graphs?ref=lapitsky.com">might discover</a> that Nixpkgs provides by far the largest and the most up-to-date collection of packages in the world. Most likely you won&apos;t have problems matching your previous OS configuration. You might want to wait with re-packaging anything bespoke using Nix depending on how familiar you are with Nix language and packaging process already.</p>
<h2 id="dotfiles-migration">Dotfiles migration</h2>
<p>Depending on the complexity &amp; sophistication of your workstation config, at this point you might be using <a href="https://nix-community.github.io/home-manager/?ref=lapitsky.com">Home Manager</a> and moving your existing app configs to your Nix repo. This could take a while and here are some tips on how to make it easier:</p>
<ul><li>Decide on the secrets management solution early on. I recommend <a href="https://github.com/Mic92/sops-nix?ref=lapitsky.com">sops-nix</a>.</li><li>Remove all your custom styling. You can progressively replace it with <a href="https://github.com/danth/stylix?ref=lapitsky.com">stylix</a>.</li><li>Don&apos;t try to migrate everything at once &#x2013; could be a lot of work</li></ul>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">Step 3: Progressively migrate your legacy dotfiles to Home Manager</div></div>
<p>I recommend taking a look at public <a href="https://github.com/linyinfeng/dotfiles/?ref=lapitsky.com">dotfiles repositories</a> on Github for inspiration.</p>
<h2 id="scaling">Scaling</h2>
<p>At some point you might notice that working with anything less than Nix brings pain and frustration. So you might consider using Nix for pretty much everything you can. I won&apos;t be the one to talk you out of it. Here are some tips:</p>
<ul><li>Use a monorepo for all configs. Structure it with <a href="https://flake.parts/?ref=lapitsky.com">flake-parts</a>.</li><li><a href="https://github.com/numtide/nixos-anywhere?ref=lapitsky.com">nix-anywhere</a> + <a href="https://github.com/nix-community/disko?ref=lapitsky.com">disko</a> to provisioning. <a href="https://github.com/serokell/deploy-rs?ref=lapitsky.com">deploy-rs</a> for remote deployments</li><li><a href="https://terranix.org/?ref=lapitsky.com">Terranix</a> + <a href="https://github.com/justinrubek/thoenix/?ref=lapitsky.com">thoenix</a> for nixifying Terraform configs</li><li><a href="https://github.com/hercules-ci/arion?ref=lapitsky.com">Arion</a> for nixifying docker-compose&apos;d services</li></ul>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">Step 4: Nixify your self-hosted fleet</div></div>
<p>Be prepared that the last steps will require effort even if you are a pretty good generalist programmer and the whole process take up to a year to get comfortable with everything.</p>
<h2 id="my-story">My story</h2>
<p>I was skeptical about Nix for a long time before switching to it and I never looked back. It&apos;s been a few years since that and my overall experience has been fun and gratifying. </p>
<p>The Nix ecosystem is evolving extremely fast and there is still a lot of room for improvement all around. I&apos;ve definitely struggled with a number of things but never actually encountered a problem I could not solve and now life became even easier with ChatGPT.</p>
<p>I&apos;d like to thank Adam H&#xF6;se (<a href="https://github.com/adisbladis?ref=lapitsky.com">Adisbladis</a>) for spending his time with me at one of the <a href="https://www.ccc.de/en/?ref=lapitsky.com">CCC</a> events and convincing me to try Nix out.</p>]]></content:encoded></item></channel></rss>