<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Gus&apos;s Blog</title><description>stuff i write!</description><link>https://gu5.org/</link><item><title>Integration testing with Nix</title><link>https://gu5.org/blog/integration-testing-nix/</link><guid isPermaLink="true">https://gu5.org/blog/integration-testing-nix/</guid><description>A nice abstraction (magical, even)</description><pubDate>Wed, 20 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve recently been working on a TypeScript client library (&lt;a href=&quot;https://github.com/thegu5/neoprom&quot;&gt;neoprom&lt;/a&gt;) for &lt;a href=&quot;https://prometheus.io&quot;&gt;Prometheus&lt;/a&gt;, which makes it easier for developers to instrument code for gathering metrics.
As part of this project, I want to have good tests that both cover the library’s internal logic, as well as make sure it works properly with Prometheus.
So… what are the options?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install Prometheus system-wide&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lots of problems: I’d rather not have it installed all the time, I’d have to wipe its database before running every test, and it’d be an extra setup step for new contributors with different steps depending on their OS (as well as their distro if on Linux).&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Spin a container up and down&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This would mean writing a messy &lt;code&gt;Containerfile&lt;/code&gt;, and adding extra steps to the test script (start, stop, wipe state).&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://nixos.org&quot;&gt;Nix&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Or… I can take advantage of the existing test framework used for testing NixOS!
Here’s a very basic example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code ::selection{background:var(--ec-uiSelBg);color:var(--ec-uiSelFg)}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre ::selection{background:var(--ec-codeSelBg);color:inherit}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root,:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code[data-theme=&apos;catppuccin-mocha&apos;]{--ec-brdRad:0.3rem;--ec-brdWd:1.5px;--ec-brdCol:#00000000;--ec-codeFontFml:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,&apos;Liberation Mono&apos;,&apos;Courier New&apos;,monospace;--ec-codeFontSize:0.85rem;--ec-codeFontWg:400;--ec-codeLineHt:1.65;--ec-codePadBlk:1rem;--ec-codePadInl:1.35rem;--ec-codeBg:#1e1e2e;--ec-codeFg:#cdd6f4;--ec-codeSelBg:#9399b240;--ec-gtrFg:#7f849cd8;--ec-gtrBrdCol:#7f849c33;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#cba6f7bb;--ec-uiFontFml:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,&apos;Segoe UI&apos;,Roboto,&apos;Helvetica Neue&apos;,Arial,&apos;Noto Sans&apos;,sans-serif,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--ec-uiFontSize:0.9rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#585b70;--ec-uiSelFg:#cdd6f4;--ec-focusBrd:#cba6f7;--ec-sbThumbCol:#585b7080;--ec-sbThumbHoverCol:#6c7086;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#18182580;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #18182580;--ec-frm-edActTabBg:#1e1e2e;--ec-frm-edActTabFg:#cba6f7;--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:#cba6f7;--ec-frm-edActTabIndBtmCol:#00000000;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.3rem;--ec-frm-edTabBarBg:#11111b;--ec-frm-edTabBarBrdCol:#00000000;--ec-frm-edTabBarBrdBtmCol:transparent;--ec-frm-edBg:#1e1e2e;--ec-frm-trmTtbFg:#cdd6f4;--ec-frm-trmTtbDotsFg:#cdd6f4;--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:#11111b;--ec-frm-trmTtbBrdBtmCol:#00000000;--ec-frm-trmBg:#1e1e2e;--ec-frm-inlBtnFg:#cdd6f4;--ec-frm-inlBtnBg:#cdd6f4;--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnBrd:#cdd6f4;--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:#5c7e59;--ec-frm-tooltipSuccessFg:white;--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])),:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code[data-theme=&apos;catppuccin-mocha&apos;] .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}@media (prefers-color-scheme: light){:root:not([data-theme=&apos;catppuccin-mocha&apos;]){--ec-codeBg:#eff1f5;--ec-codeFg:#4c4f69;--ec-codeSelBg:#7c7f934d;--ec-gtrFg:#808393;--ec-gtrBrdCol:#80839333;--ec-gtrHlFg:#8839ef;--ec-uiSelBg:#acb0be;--ec-uiSelFg:#4c4f69;--ec-focusBrd:#8839ef;--ec-sbThumbCol:#acb0be80;--ec-sbThumbHoverCol:#9599a8;--ec-tm-markBg:#9fb6ff80;--ec-tm-insBg:#94c68480;--ec-tm-insDiffIndCol:#3a692fd0;--ec-tm-delBg:#fea09280;--ec-tm-delDiffIndCol:#97453dd0;--ec-frm-shdCol:#e6e9ef80;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #e6e9ef80;--ec-frm-edActTabBg:#eff1f5;--ec-frm-edActTabFg:#8839ef;--ec-frm-edActTabIndTopCol:#8839ef;--ec-frm-edTabBarBg:#dce0e8;--ec-frm-edBg:#eff1f5;--ec-frm-trmTtbFg:#4c4f69;--ec-frm-trmTtbDotsFg:#4c4f69;--ec-frm-trmTtbBg:#dce0e8;--ec-frm-trmBg:#eff1f5;--ec-frm-inlBtnFg:#4c4f69;--ec-frm-inlBtnBg:#4c4f69;--ec-frm-inlBtnBrd:#4c4f69;--ec-frm-tooltipSuccessBg:#358524}:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--1, inherit);background-color:var(--1bg, transparent);font-style:var(--1fs, inherit);font-weight:var(--1fw, inherit);text-decoration:var(--1td, inherit)}}:root[data-theme=&apos;catppuccin-latte&apos;] .expressive-code:not([data-theme=&apos;catppuccin-mocha&apos;]),.expressive-code[data-theme=&apos;catppuccin-latte&apos;]{--ec-codeBg:#eff1f5;--ec-codeFg:#4c4f69;--ec-codeSelBg:#7c7f934d;--ec-gtrFg:#808393;--ec-gtrBrdCol:#80839333;--ec-gtrHlFg:#8839ef;--ec-uiSelBg:#acb0be;--ec-uiSelFg:#4c4f69;--ec-focusBrd:#8839ef;--ec-sbThumbCol:#acb0be80;--ec-sbThumbHoverCol:#9599a8;--ec-tm-markBg:#9fb6ff80;--ec-tm-insBg:#94c68480;--ec-tm-insDiffIndCol:#3a692fd0;--ec-tm-delBg:#fea09280;--ec-tm-delDiffIndCol:#97453dd0;--ec-frm-shdCol:#e6e9ef80;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #e6e9ef80;--ec-frm-edActTabBg:#eff1f5;--ec-frm-edActTabFg:#8839ef;--ec-frm-edActTabIndTopCol:#8839ef;--ec-frm-edTabBarBg:#dce0e8;--ec-frm-edBg:#eff1f5;--ec-frm-trmTtbFg:#4c4f69;--ec-frm-trmTtbDotsFg:#4c4f69;--ec-frm-trmTtbBg:#dce0e8;--ec-frm-trmBg:#eff1f5;--ec-frm-inlBtnFg:#4c4f69;--ec-frm-inlBtnBg:#4c4f69;--ec-frm-inlBtnBrd:#4c4f69;--ec-frm-tooltipSuccessBg:#358524}:root[data-theme=&apos;catppuccin-latte&apos;] .expressive-code:not([data-theme=&apos;catppuccin-mocha&apos;]) .ec-line :where(span[style^=&apos;--&apos;]:not([class])),.expressive-code[data-theme=&apos;catppuccin-latte&apos;] .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--1, inherit);background-color:var(--1bg, transparent);font-style:var(--1fs, inherit);font-weight:var(--1fw, inherit);text-decoration:var(--1td, inherit)}&lt;/style&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#EBA0AC;--0fs:italic;--1:#AD343E;--1fs:italic&quot;&gt;pkgs&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;pkgs&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;testers&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;runNixOSTest &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;ping test&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;containers&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;machine1&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;machine2&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;testScript&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;start_all()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;machine1.succeed(&quot;ping -c 1 machine2&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;machine2.succeed(&quot;ping -c 1 machine1&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{ pkgs }:pkgs.testers.runNixOSTest {  name = &amp;quot;ping test&amp;quot;;  containers = {    machine1 = { };    machine2 = { };  };  testScript = &amp;#x27;&amp;#x27;    start_all()    machine1.succeed(&amp;quot;ping -c 1 machine2&amp;quot;)    machine2.succeed(&amp;quot;ping -c 1 machine1&amp;quot;)  &amp;#x27;&amp;#x27;;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When ran, it starts two containers, then has them ping each other.&lt;/p&gt;
&lt;p&gt;The true power of this tool comes with being able to assign each machine a NixOS configuration:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#EBA0AC;--0fs:italic;--1:#AD343E;--1fs:italic&quot;&gt;pkgs&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#EBA0AC;--0fs:italic;--1:#AD343E;--1fs:italic&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#EBA0AC;--0fs:italic;--1:#AD343E;--1fs:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;pkgs&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;testers&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;runNixOSTest &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;more advanced test&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;containers&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#EBA0AC;--0fs:italic;--1:#AD343E;--1fs:italic&quot;&gt;pkgs&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;... &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;environment&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;systemPackages&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; pkgs&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;prometheus&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;cli &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;systemd&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;services&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;metrics&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;wantedBy&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;multi-user.target&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;serviceConfig&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;ExecStart&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;getExe&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;pkgs&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;nodejs&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;/some-server.ts&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;services&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;prometheus&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;enable&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F38BA8;--1:#C00E34&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--0fs:italic;--1:#5D5F6E;--1fs:italic&quot;&gt;# more configuration...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;testScript&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;start_all()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;app.wait_for_unit(&quot;metrics.service&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;app.wait_for_unit(&quot;prometheus.service&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;app.wait_for_open_port(9000)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;app.wait_for_open_port(9090)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;data = app.succeed(&quot;promtool query instant http://localhost:9090 some_total&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  pkgs,  lib,  src,}:pkgs.testers.runNixOSTest {  name = &amp;quot;more advanced test&amp;quot;;  containers.app =    { pkgs, ... }:    {      environment.systemPackages = [ pkgs.prometheus.cli ];      systemd.services.metrics = {        wantedBy = [ &amp;quot;multi-user.target&amp;quot; ];        serviceConfig.ExecStart = &amp;quot;${lib.getExe pkgs.nodejs} ${src}/some-server.ts&amp;quot;;      };      services.prometheus = {        enable = true;        # more configuration...      };    };  testScript = &amp;#x27;&amp;#x27;    start_all()    app.wait_for_unit(&amp;quot;metrics.service&amp;quot;)    app.wait_for_unit(&amp;quot;prometheus.service&amp;quot;)    app.wait_for_open_port(9000)    app.wait_for_open_port(9090)    data = app.succeed(&amp;quot;promtool query instant http://localhost:9090 some_total&amp;quot;)    # ...  &amp;#x27;&amp;#x27;;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The specific command to run the test depends on the project’s setup.
You can look at &lt;a href=&quot;https://github.com/thegu5/neoprom/blob/main/package.json&quot;&gt;my non-flake setup&lt;/a&gt; for inspiration, or take a peek at Jacek Galowicz’s work below (Nixcademy).&lt;/p&gt;
&lt;p&gt;Thanks for reading :)&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://nixcademy.com/posts/faster-cheaper-nixos-integration-tests-with-containers/&quot;&gt;https://nixcademy.com/posts/faster-cheaper-nixos-integration-tests-with-containers/&lt;/a&gt;
(&lt;a href=&quot;https://github.com/applicative-systems/nixos-test-driver-nixcon&quot;&gt;slides &amp;amp; example repo&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nixos.org/manual/nixos/unstable/#sec-nixos-tests&quot;&gt;https://nixos.org/manual/nixos/unstable/#sec-nixos-tests&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nix.dev/tutorials/nixos/integration-testing-using-virtual-machines.html&quot;&gt;https://nix.dev/tutorials/nixos/integration-testing-using-virtual-machines.html&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>post</category><category>testing</category><category>nix</category></item><item><title>Run your own Matrix homeserver on NixOS</title><link>https://gu5.org/blog/matrix-homeserver-nixos/</link><guid isPermaLink="true">https://gu5.org/blog/matrix-homeserver-nixos/</guid><description>The power of nix!</description><pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Due to &lt;a href=&quot;https://slate.com/technology/2026/02/discord-id-age-verification-online-safety.html&quot;&gt;current events&lt;/a&gt;,
alternatives to Discord have been getting a lot of attention recently. As much as I would love for &lt;a href=&quot;https://matrix.org/&quot;&gt;Matrix&lt;/a&gt; to
succeed here, it isn’t ready for most non-technical users. However, if you want to tinker…&lt;/p&gt;
&lt;p&gt;This guide assumes a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You’ll be running the server on a computer that’s publically accessible over the internet&lt;/li&gt;
&lt;li&gt;You have a domain that points to said machine&lt;/li&gt;
&lt;li&gt;Said machine is running &lt;a href=&quot;https://nixos.org/&quot;&gt;NixOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since “Matrix” is a protocol, there are several server implementations - with the most widely used (by far) being &lt;a href=&quot;https://github.com/element-hq/synapse&quot;&gt;Synapse&lt;/a&gt;.
It was the first implementation, and it’s used to host the official &lt;code&gt;matrix.org&lt;/code&gt; server - however, it has performance issues and eats a bunch of RAM and CPU.
The main alternative, which is what this guide will use, is &lt;a href=&quot;https://continuwuity.org/&quot;&gt;Continuwuity&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Continuwuity is packaged in nixpkgs and already has a NixOS module,
which makes the setup process just involve enabling the service and some settings:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code ::selection{background:var(--ec-uiSelBg);color:var(--ec-uiSelFg)}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre ::selection{background:var(--ec-codeSelBg);color:inherit}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root,:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code[data-theme=&apos;catppuccin-mocha&apos;]{--ec-brdRad:0.3rem;--ec-brdWd:1.5px;--ec-brdCol:#00000000;--ec-codeFontFml:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,&apos;Liberation Mono&apos;,&apos;Courier New&apos;,monospace;--ec-codeFontSize:0.85rem;--ec-codeFontWg:400;--ec-codeLineHt:1.65;--ec-codePadBlk:1rem;--ec-codePadInl:1.35rem;--ec-codeBg:#1e1e2e;--ec-codeFg:#cdd6f4;--ec-codeSelBg:#9399b240;--ec-gtrFg:#7f849cd8;--ec-gtrBrdCol:#7f849c33;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#cba6f7bb;--ec-uiFontFml:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,&apos;Segoe UI&apos;,Roboto,&apos;Helvetica Neue&apos;,Arial,&apos;Noto Sans&apos;,sans-serif,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--ec-uiFontSize:0.9rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#585b70;--ec-uiSelFg:#cdd6f4;--ec-focusBrd:#cba6f7;--ec-sbThumbCol:#585b7080;--ec-sbThumbHoverCol:#6c7086;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#18182580;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #18182580;--ec-frm-edActTabBg:#1e1e2e;--ec-frm-edActTabFg:#cba6f7;--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:#cba6f7;--ec-frm-edActTabIndBtmCol:#00000000;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.3rem;--ec-frm-edTabBarBg:#11111b;--ec-frm-edTabBarBrdCol:#00000000;--ec-frm-edTabBarBrdBtmCol:transparent;--ec-frm-edBg:#1e1e2e;--ec-frm-trmTtbFg:#cdd6f4;--ec-frm-trmTtbDotsFg:#cdd6f4;--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:#11111b;--ec-frm-trmTtbBrdBtmCol:#00000000;--ec-frm-trmBg:#1e1e2e;--ec-frm-inlBtnFg:#cdd6f4;--ec-frm-inlBtnBg:#cdd6f4;--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnBrd:#cdd6f4;--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:#5c7e59;--ec-frm-tooltipSuccessFg:white;--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])),:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code[data-theme=&apos;catppuccin-mocha&apos;] .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}@media (prefers-color-scheme: light){:root:not([data-theme=&apos;catppuccin-mocha&apos;]){--ec-codeBg:#eff1f5;--ec-codeFg:#4c4f69;--ec-codeSelBg:#7c7f934d;--ec-gtrFg:#808393;--ec-gtrBrdCol:#80839333;--ec-gtrHlFg:#8839ef;--ec-uiSelBg:#acb0be;--ec-uiSelFg:#4c4f69;--ec-focusBrd:#8839ef;--ec-sbThumbCol:#acb0be80;--ec-sbThumbHoverCol:#9599a8;--ec-tm-markBg:#9fb6ff80;--ec-tm-insBg:#94c68480;--ec-tm-insDiffIndCol:#3a692fd0;--ec-tm-delBg:#fea09280;--ec-tm-delDiffIndCol:#97453dd0;--ec-frm-shdCol:#e6e9ef80;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #e6e9ef80;--ec-frm-edActTabBg:#eff1f5;--ec-frm-edActTabFg:#8839ef;--ec-frm-edActTabIndTopCol:#8839ef;--ec-frm-edTabBarBg:#dce0e8;--ec-frm-edBg:#eff1f5;--ec-frm-trmTtbFg:#4c4f69;--ec-frm-trmTtbDotsFg:#4c4f69;--ec-frm-trmTtbBg:#dce0e8;--ec-frm-trmBg:#eff1f5;--ec-frm-inlBtnFg:#4c4f69;--ec-frm-inlBtnBg:#4c4f69;--ec-frm-inlBtnBrd:#4c4f69;--ec-frm-tooltipSuccessBg:#358524}:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--1, inherit);background-color:var(--1bg, transparent);font-style:var(--1fs, inherit);font-weight:var(--1fw, inherit);text-decoration:var(--1td, inherit)}}:root[data-theme=&apos;catppuccin-latte&apos;] .expressive-code:not([data-theme=&apos;catppuccin-mocha&apos;]),.expressive-code[data-theme=&apos;catppuccin-latte&apos;]{--ec-codeBg:#eff1f5;--ec-codeFg:#4c4f69;--ec-codeSelBg:#7c7f934d;--ec-gtrFg:#808393;--ec-gtrBrdCol:#80839333;--ec-gtrHlFg:#8839ef;--ec-uiSelBg:#acb0be;--ec-uiSelFg:#4c4f69;--ec-focusBrd:#8839ef;--ec-sbThumbCol:#acb0be80;--ec-sbThumbHoverCol:#9599a8;--ec-tm-markBg:#9fb6ff80;--ec-tm-insBg:#94c68480;--ec-tm-insDiffIndCol:#3a692fd0;--ec-tm-delBg:#fea09280;--ec-tm-delDiffIndCol:#97453dd0;--ec-frm-shdCol:#e6e9ef80;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #e6e9ef80;--ec-frm-edActTabBg:#eff1f5;--ec-frm-edActTabFg:#8839ef;--ec-frm-edActTabIndTopCol:#8839ef;--ec-frm-edTabBarBg:#dce0e8;--ec-frm-edBg:#eff1f5;--ec-frm-trmTtbFg:#4c4f69;--ec-frm-trmTtbDotsFg:#4c4f69;--ec-frm-trmTtbBg:#dce0e8;--ec-frm-trmBg:#eff1f5;--ec-frm-inlBtnFg:#4c4f69;--ec-frm-inlBtnBg:#4c4f69;--ec-frm-inlBtnBrd:#4c4f69;--ec-frm-tooltipSuccessBg:#358524}:root[data-theme=&apos;catppuccin-latte&apos;] .expressive-code:not([data-theme=&apos;catppuccin-mocha&apos;]) .ec-line :where(span[style^=&apos;--&apos;]:not([class])),.expressive-code[data-theme=&apos;catppuccin-latte&apos;] .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--1, inherit);background-color:var(--1bg, transparent);font-style:var(--1fs, inherit);font-weight:var(--1fw, inherit);text-decoration:var(--1td, inherit)}&lt;/style&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CBA6F7;--1:#7B34D9&quot;&gt;let&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;your-domain&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;example.com&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CBA6F7;--1:#7B34D9&quot;&gt;in&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;services&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;matrix-continuwuity = &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;enable&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F38BA8;--1:#C00E34&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;settings&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;global&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;server_name&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; your-domain&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;new_user_displayname_suffix&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F38BA8;--1:#C00E34&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;unix_socket_path&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;/run/continuwuity/continuwuity.sock&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;well_known&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;https://matrix.&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;your-domain&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;well_known&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;matrix.&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;your-domain&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;:443&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--0fs:italic;--1:#5D5F6E;--1fs:italic&quot;&gt;# just in case!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;lockdown_public_room_directory&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F38BA8;--1:#C00E34&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;allow_room_creation&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F38BA8;--1:#C00E34&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;require_auth_for_profile_requests&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F38BA8;--1:#C00E34&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--0fs:italic;--1:#5D5F6E;--1fs:italic&quot;&gt;# no user enumeration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;url_preview_domain_explicit_allowlist&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;github.com&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;INFO,conduwuit_core::matrix::state_res=off&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--0fs:italic;--1:#5D5F6E;--1fs:italic&quot;&gt;# cleaner logs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let    your-domain = &amp;quot;example.com&amp;quot;;inservices.matrix-continuwuity = {    enable = true;    settings.global = {        server_name = your-domain;        new_user_displayname_suffix = &amp;quot;&amp;quot;;        address = null;        unix_socket_path = &amp;quot;/run/continuwuity/continuwuity.sock&amp;quot;;        well_known.client = &amp;quot;https://matrix.${your-domain}&amp;quot;;        well_known.server = &amp;quot;matrix.${your-domain}:443&amp;quot;;        # just in case!        lockdown_public_room_directory = true;        allow_room_creation = false;        require_auth_for_profile_requests = true; # no user enumeration        url_preview_domain_explicit_allowlist = [ &amp;quot;github.com&amp;quot; ];        log = &amp;quot;INFO,conduwuit_core::matrix::state_res=off&amp;quot;; # cleaner logs    };  };&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We also need to expose the server to the public internet. &lt;a href=&quot;https://caddyserver.com/&quot;&gt;Caddy&lt;/a&gt; makes this super easy, handles TLS certificates automatically, etc.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CBA6F7;--1:#7B34D9&quot;&gt;let&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;your-domain&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;example.com&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CBA6F7;--1:#7B34D9&quot;&gt;in&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;services&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;caddy = &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;enable&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#F38BA8;--1:#C00E34&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;virtualHosts&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;your-domain&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;extraConfig&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;reverse_proxy /.well-known/matrix/* unix//run/continuwuity/continuwuity.sock&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;matrix.&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;your-domain&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1A57D1&quot;&gt;extraConfig&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;route {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;@api path /_matrix/* /_continuwuity/*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;reverse_proxy @api unix//run/continuwuity/continuwuity.sock&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;caddy&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;extraGroups = &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;continuwuity&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--0fs:italic;--1:#5D5F6E;--1fs:italic&quot;&gt;# give caddy access to continuwuity&apos;s unix socket&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;networking&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;firewall&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;allowedTCPPorts = &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FAB387;--1:#A54107&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FAB387;--1:#A54107&quot;&gt;443&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;networking&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;firewall&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;allowedUDPPorts = &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FAB387;--1:#A54107&quot;&gt;443&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let    your-domain = &amp;quot;example.com&amp;quot;;inservices.caddy = {    enable = true;    virtualHosts = {        &amp;quot;${your-domain}&amp;quot;.extraConfig = &amp;#x27;&amp;#x27;            reverse_proxy /.well-known/matrix/* unix//run/continuwuity/continuwuity.sock        &amp;#x27;&amp;#x27;;        &amp;quot;matrix.${your-domain}&amp;quot;.extraConfig = &amp;#x27;&amp;#x27;            route {                @api path /_matrix/* /_continuwuity/*                reverse_proxy @api unix//run/continuwuity/continuwuity.sock            }        &amp;#x27;&amp;#x27;;    };};users.users.caddy.extraGroups = [ &amp;quot;continuwuity&amp;quot; ]; # give caddy access to continuwuity&amp;#x27;s unix socketnetworking.firewall.allowedTCPPorts = [ 80 443 ];networking.firewall.allowedUDPPorts = [ 443 ];&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;To test that the server is accessible to the wider network, you can use the &lt;a href=&quot;https://federationtester.matrix.org/&quot;&gt;Matrix Federation Tester&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that the server is up, running and working, you need a client to use to connect. I prefer &lt;a href=&quot;https://cinny.in/&quot;&gt;Cinny&lt;/a&gt; since it’s a self-contained web application and has a good UI, but there are &lt;a href=&quot;https://matrix.org/ecosystem/clients/&quot;&gt;many others&lt;/a&gt;. You can use the official instance the developer runs at &lt;a href=&quot;https://app.cinny.im&quot;&gt;app.cinny.im&lt;/a&gt;, or deploy your own:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;nix&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;matrix.&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#4C5AA8&quot;&gt;your-domain&lt;/span&gt;&lt;span style=&quot;--0:#9399B2;--1:#5D5F6E&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;extraConfig = &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;route {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;@api path /_matrix/* /_continuwuity/*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;reverse_proxy @api unix//run/continuwuity/continuwuity.sock&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#245918&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1&quot;&gt;root * &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;${&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#3e4989&quot;&gt;pkgs&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#3e4989&quot;&gt;cinny&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#3e4989&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;conf&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;defaultHomeserver&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FAB387;--1:#863506&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;homeserverList&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B4BEFE;--1:#3e4989&quot;&gt;your-domain&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;allowCustomHomeservers&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#f390ab;--1:#9c0b2a&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;featuredCommunities&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;openAsDefault&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#f390ab;--1:#9c0b2a&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;spaces&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                            &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt;&quot;#community:matrix.org&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                            &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt;&quot;#cinny-space:matrix.org&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                            &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt;&quot;#space:continuwuity.org&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                            &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt;&quot;#space:nixos.org&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;rooms&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--1:#1547aa&quot;&gt;servers&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#0e575b&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                            &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt;&quot;matrix.org&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                            &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt;&quot;mozilla.org&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                            &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#245918&quot;&gt;&quot;nixos.org&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                        &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#a8adc1;--1:#4c4d59&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#245918&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1&quot;&gt;try_files {path} / index.html&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight ins&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#245918&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1&quot;&gt;file_server&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;quot;matrix.${your-domain}&amp;quot;.extraConfig = &amp;#x27;&amp;#x27;    route {        @api path /_matrix/* /_continuwuity/*        reverse_proxy @api unix//run/continuwuity/continuwuity.sock        root * ${            pkgs.cinny.override {                conf = {                    defaultHomeserver = 0;                    homeserverList = [ your-domain ];                    allowCustomHomeservers = false;                    featuredCommunities = {                        openAsDefault = false;                        spaces = [                            &amp;quot;#community:matrix.org&amp;quot;                            &amp;quot;#cinny-space:matrix.org&amp;quot;                            &amp;quot;#space:continuwuity.org&amp;quot;                            &amp;quot;#space:nixos.org&amp;quot;                        ];                        rooms = [ ];                        servers = [                            &amp;quot;matrix.org&amp;quot;                            &amp;quot;mozilla.org&amp;quot;                            &amp;quot;nixos.org&amp;quot;                        ];                    };                };            }        }        try_files {path} / index.html        file_server    }&amp;#x27;&amp;#x27;;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now it’s time to register your account! Your client will ask for a registration token, which is in the service logs:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#89B4FA;--0fs:italic;--1:#1A57D1;--1fs:italic&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;-u&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;continuwuity&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--0fs:italic;--1:#1A57D1;--1fs:italic&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;registration token&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo journalctl -u continuwuity | grep &amp;quot;registration token&amp;quot;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you run into any issues, the &lt;a href=&quot;https://matrix.to/#/#space:continuwuity.org&quot;&gt;Continuwuity matrix space&lt;/a&gt; is super active and helpful. You might need to create an account on different server like &lt;code&gt;matrix.org&lt;/code&gt; if your own isn’t fully set up yet :)&lt;/p&gt;
&lt;section data-footnotes=&quot;&quot; class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Of all the non-synapse servers - &lt;a href=&quot;https://github.com/element-hq/dendrite&quot;&gt;Dendrite&lt;/a&gt; is in maintenance mode, &lt;a href=&quot;https://conduit.rs/&quot;&gt;Conduit&lt;/a&gt; has less active development, and the primary maintainer of &lt;a href=&quot;https://github.com/matrix-construct/tuwunel&quot;&gt;Tuwunel&lt;/a&gt; is banned by the Matrix Foundation &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded><category>howto</category><category>matrix</category><category>nix</category></item><item><title>Testing</title><link>https://gu5.org/blog/test/</link><guid isPermaLink="true">https://gu5.org/blog/test/</guid><description>is this thing on?</description><pubDate>Thu, 05 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a test blog post to make sure everything is working right!&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code ::selection{background:var(--ec-uiSelBg);color:var(--ec-uiSelFg)}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre ::selection{background:var(--ec-codeSelBg);color:inherit}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root,:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code[data-theme=&apos;catppuccin-mocha&apos;]{--ec-brdRad:0.3rem;--ec-brdWd:1.5px;--ec-brdCol:#00000000;--ec-codeFontFml:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,&apos;Liberation Mono&apos;,&apos;Courier New&apos;,monospace;--ec-codeFontSize:0.85rem;--ec-codeFontWg:400;--ec-codeLineHt:1.65;--ec-codePadBlk:1rem;--ec-codePadInl:1.35rem;--ec-codeBg:#1e1e2e;--ec-codeFg:#cdd6f4;--ec-codeSelBg:#9399b240;--ec-gtrFg:#7f849cd8;--ec-gtrBrdCol:#7f849c33;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#cba6f7bb;--ec-uiFontFml:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,&apos;Segoe UI&apos;,Roboto,&apos;Helvetica Neue&apos;,Arial,&apos;Noto Sans&apos;,sans-serif,&apos;Apple Color Emoji&apos;,&apos;Segoe UI Emoji&apos;,&apos;Segoe UI Symbol&apos;,&apos;Noto Color Emoji&apos;;--ec-uiFontSize:0.9rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#585b70;--ec-uiSelFg:#cdd6f4;--ec-focusBrd:#cba6f7;--ec-sbThumbCol:#585b7080;--ec-sbThumbHoverCol:#6c7086;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#18182580;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #18182580;--ec-frm-edActTabBg:#1e1e2e;--ec-frm-edActTabFg:#cba6f7;--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:#cba6f7;--ec-frm-edActTabIndBtmCol:#00000000;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.3rem;--ec-frm-edTabBarBg:#11111b;--ec-frm-edTabBarBrdCol:#00000000;--ec-frm-edTabBarBrdBtmCol:transparent;--ec-frm-edBg:#1e1e2e;--ec-frm-trmTtbFg:#cdd6f4;--ec-frm-trmTtbDotsFg:#cdd6f4;--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:#11111b;--ec-frm-trmTtbBrdBtmCol:#00000000;--ec-frm-trmBg:#1e1e2e;--ec-frm-inlBtnFg:#cdd6f4;--ec-frm-inlBtnBg:#cdd6f4;--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnBrd:#cdd6f4;--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:#5c7e59;--ec-frm-tooltipSuccessFg:white;--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])),:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code[data-theme=&apos;catppuccin-mocha&apos;] .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}@media (prefers-color-scheme: light){:root:not([data-theme=&apos;catppuccin-mocha&apos;]){--ec-codeBg:#eff1f5;--ec-codeFg:#4c4f69;--ec-codeSelBg:#7c7f934d;--ec-gtrFg:#808393;--ec-gtrBrdCol:#80839333;--ec-gtrHlFg:#8839ef;--ec-uiSelBg:#acb0be;--ec-uiSelFg:#4c4f69;--ec-focusBrd:#8839ef;--ec-sbThumbCol:#acb0be80;--ec-sbThumbHoverCol:#9599a8;--ec-tm-markBg:#9fb6ff80;--ec-tm-insBg:#94c68480;--ec-tm-insDiffIndCol:#3a692fd0;--ec-tm-delBg:#fea09280;--ec-tm-delDiffIndCol:#97453dd0;--ec-frm-shdCol:#e6e9ef80;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #e6e9ef80;--ec-frm-edActTabBg:#eff1f5;--ec-frm-edActTabFg:#8839ef;--ec-frm-edActTabIndTopCol:#8839ef;--ec-frm-edTabBarBg:#dce0e8;--ec-frm-edBg:#eff1f5;--ec-frm-trmTtbFg:#4c4f69;--ec-frm-trmTtbDotsFg:#4c4f69;--ec-frm-trmTtbBg:#dce0e8;--ec-frm-trmBg:#eff1f5;--ec-frm-inlBtnFg:#4c4f69;--ec-frm-inlBtnBg:#4c4f69;--ec-frm-inlBtnBrd:#4c4f69;--ec-frm-tooltipSuccessBg:#358524}:root:not([data-theme=&apos;catppuccin-mocha&apos;]) .expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--1, inherit);background-color:var(--1bg, transparent);font-style:var(--1fs, inherit);font-weight:var(--1fw, inherit);text-decoration:var(--1td, inherit)}}:root[data-theme=&apos;catppuccin-latte&apos;] .expressive-code:not([data-theme=&apos;catppuccin-mocha&apos;]),.expressive-code[data-theme=&apos;catppuccin-latte&apos;]{--ec-codeBg:#eff1f5;--ec-codeFg:#4c4f69;--ec-codeSelBg:#7c7f934d;--ec-gtrFg:#808393;--ec-gtrBrdCol:#80839333;--ec-gtrHlFg:#8839ef;--ec-uiSelBg:#acb0be;--ec-uiSelFg:#4c4f69;--ec-focusBrd:#8839ef;--ec-sbThumbCol:#acb0be80;--ec-sbThumbHoverCol:#9599a8;--ec-tm-markBg:#9fb6ff80;--ec-tm-insBg:#94c68480;--ec-tm-insDiffIndCol:#3a692fd0;--ec-tm-delBg:#fea09280;--ec-tm-delDiffIndCol:#97453dd0;--ec-frm-shdCol:#e6e9ef80;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #e6e9ef80;--ec-frm-edActTabBg:#eff1f5;--ec-frm-edActTabFg:#8839ef;--ec-frm-edActTabIndTopCol:#8839ef;--ec-frm-edTabBarBg:#dce0e8;--ec-frm-edBg:#eff1f5;--ec-frm-trmTtbFg:#4c4f69;--ec-frm-trmTtbDotsFg:#4c4f69;--ec-frm-trmTtbBg:#dce0e8;--ec-frm-trmBg:#eff1f5;--ec-frm-inlBtnFg:#4c4f69;--ec-frm-inlBtnBg:#4c4f69;--ec-frm-inlBtnBrd:#4c4f69;--ec-frm-tooltipSuccessBg:#358524}:root[data-theme=&apos;catppuccin-latte&apos;] .expressive-code:not([data-theme=&apos;catppuccin-mocha&apos;]) .ec-line :where(span[style^=&apos;--&apos;]:not([class])),.expressive-code[data-theme=&apos;catppuccin-latte&apos;] .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--1, inherit);background-color:var(--1bg, transparent);font-style:var(--1fs, inherit);font-weight:var(--1fw, inherit);text-decoration:var(--1td, inherit)}&lt;/style&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#94E2D5;--1:#116B70&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#89B4FA;--0fs:italic;--1:#1A57D1;--1fs:italic&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A6E3A1;--1:#2C6E1E&quot;&gt;&quot;hello!&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CDD6F4;--1:#4C4F69&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;console.log(&amp;quot;hello!&amp;quot;)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
</content:encoded><category>note</category><category>meta</category></item></channel></rss>