Error: user-error ("Unable to resolve link: \"*Guix Configuration as a Channel\"")
mapbacktrace(#f(compiled-function (evald func args flags) #))
debug-early-backtrace()
debug-early(error (user-error "Unable to resolve link: \"*Guix Configuration as a Channel\""))
signal(user-error ("Unable to resolve link: \"*Guix Configuration as a Channel\""))
user-error("Unable to resolve link: %S" "*Guix Configuration as a Channel")
org-export-data((link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #70))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #116))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #162))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #208) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #211)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #211)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #211) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #224))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #211) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #225))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #211) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #226))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #211) #("Earlier this year " 0 18 (:parent #227)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #227) #("I announced on the guix mailing list" 0 36 (:parent #231))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #227)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #212))) :mode nil :granularity nil :parent #208) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #212) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #215) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #218))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #215) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #219) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #222) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #225) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #228) #("Improved Build Diversity" 0 24 (:parent #231)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #225)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #219) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #223) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #226) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #229) #("Reduced Latency" 0 15 (:parent #232)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #226)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #219) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #224) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #227) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #230) #("Increased Resilience" 0 20 (:parent #233)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #227)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #219) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #225) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #228) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #231) #("Community Contribution" 0 22 (:parent #234)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #228))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #215) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #220)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #220) #("here" 0 4 (:parent #224))) #(".\n" 0 2 (:parent #220))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #213))) :mode nil :granularity nil :parent #208) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #213) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #216) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #219))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #216) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #223) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #226) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #229) #("Processor" 0 9 (:parent #232)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #226)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #224) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #227) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #230) #("RAM" 0 3 (:parent #233)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #227)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #225) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #228) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #231) #("Storage" 0 7 (:parent #234)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #228)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #226) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #229) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #232) #("Network" 0 7 (:parent #235)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #229)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #227) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #230) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #233) #("Location" 0 8 (:parent #236)))) #(": Memphis TN\n" 0 13 (:parent #230))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #216) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #221))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #216) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #222))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #216) #("For more details, see the " 0 26 (:parent #223)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #223) #("Specifications section" 0 22 (:parent #227))) #("of the Cuirass Manual.\n" 0 23 (:parent #223))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #216) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #224))))) #162)) #116 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #166))) :mode nil :granularity nil :parent #162) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #166) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #169) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #172)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #172) #("guix publish" 0 12 (:parent #176))) #(", which Guix provides the " 0 26 (:parent #172)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #172) #("guix-publish-service-type" 0 25 (:parent #178))) #(",\nwhich is used in the " 0 23 (:parent #172)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #172)) #("field of " 0 9 (:parent #172)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #172)) #("definition.\n" 0 12 (:parent #172))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #169)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #169) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #174))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #167))) :mode nil :granularity nil :parent #162) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #167) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #170) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #173))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #170) #("To anonymize nginx access logs, the " 0 36 (:parent #174)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #174) #("anonip-service-type" 0 19 (:parent #178))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #174)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #174)) #("is defined.\n" 0 12 (:parent #174))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #170)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #170) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #176))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #170)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #170) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #178)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #178)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #178))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #170)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #170) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #180)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #180)) #("field of our\n" 0 13 (:parent #180)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #180)) #("declaration.\n" 0 13 (:parent #180))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #170)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #168))) :mode nil :granularity nil :parent #162) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #168) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #171) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #174)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #172))) :mode nil :granularity nil :parent #168) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #172) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #175) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #178)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #178) #("letsencrypt" 0 11 (:parent #182))) #("via the " 0 8 (:parent #178)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #178) #("certbot" 0 7 (:parent #184))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #178)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #178) #("certbox-service-type" 0 20 (:parent #186))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #178)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #178)) #("field in our " 0 13 (:parent #178)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #178)) #("configuration.\n" 0 15 (:parent #178))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #175)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #175) #("This service references " 0 24 (:parent #180)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #180)) #(", which we define below. It sends " 0 34 (:parent #180)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #180)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #180))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #175)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #175) #("Next we define a function we will use later in the " 0 51 (:parent #182)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #182) #("Configure Nginx Server Blocks" 0 29 (:parent #186))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #182))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #175)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #173)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #173))) :mode nil :granularity nil :parent #168) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #173) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #176) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #179))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #176)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #176) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #181))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #176) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #182) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #185) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #188)) #("\n" 0 1 (:parent #188))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #185) #(" " 0 2 (:parent #189)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #189)) #("provides a route " 0 17 (:parent #189)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #189)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #189)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #189)) #("command). Given away by the reference to " 0 41 (:parent #189)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #189) #("Nix" 0 3 (:parent #199))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #189)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #189) #("Nix Binary Cache" 0 16 (:parent #201))) #(".\n" 0 2 (:parent #189))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #185) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #190))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #185)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #185) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #192))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #185))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #182) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #186) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #189)) #("\n" 0 1 (:parent #189))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #186) #(" " 0 2 (:parent #190)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #190) #("NAR (Nix Archive Format)" 0 24 (:parent #194))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #190)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #190) #("hello" 0 5 (:parent #196))) #("package.\n" 0 9 (:parent #190))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #186) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #191))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #186)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #186)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #186) #(" The result is composed of a few parts:\n" 0 41 (:parent #194))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #186) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #198))) :mode item :granularity nil :parent #195) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #198) #("the guix store path\n" 0 20 (:parent #201)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #199))) :mode item :granularity nil :parent #195) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #199) #("a hash uniquely identifying the store item\n" 0 43 (:parent #202)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #200))) :mode item :granularity nil :parent #195) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #200) #("the package-name and version, separated by dashes\n" 0 50 (:parent #203))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #186) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #196)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #196)) #(".\n" 0 2 (:parent #196))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #186))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #182) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #187) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #190)) #("\n" 0 1 (:parent #190))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #187) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #191)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #191)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #191)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #191)) #("file.\n" 0 6 (:parent #191))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #187)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #187)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #187) #(" If the package is not available, this would return a " 0 55 (:parent #194)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #194)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #194)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #194)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #194)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #194)) #("below.\n" 0 7 (:parent #194))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #187) #(" #+begin" 0 9 (:parent #195)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #195) #("src" 0 3 (:parent #199))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #195)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #195) #("nar" 0 3 (:parent #201))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #195)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #195) #("pass" 0 4 (:parent #203))) #("\" url \";\")\n \"client" 0 25 (:parent #195)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #195) #("body" 0 4 (:parent #205))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #195) #("buffer" 0 6 (:parent #206))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #195) #("size" 0 4 (:parent #207))) #("256k;\"\n" 0 7 (:parent #195)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #116) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #119) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #122)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #122) #("Guix channels" 0 13 (:parent #126))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #122)))) #70 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #121))) :mode nil :granularity nil :parent #116) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #121) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #124) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #127)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #127)) #("field of our " 0 13 (:parent #127)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #127)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #127))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #124)))))) #46)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #46) #("In order to run Cuirass via the " 0 32 (:parent #49)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #49)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #49)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #49)) #("as a " 0 5 (:parent #49)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #49) #("G-Expression" 0 12 (:parent #57))) #("that will return a list of\n" 0 27 (:parent #49)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #49) #("cuirass specifications" 0 22 (:parent #59))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #49))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #46)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #46) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #51)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #51)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #51)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #51) #("Cuirass specification" 0 21 (:parent #57))) #("\ndocumentation for more details.\n" 0 33 (:parent #51))) #26)) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #26)) #0 #(".\n" 0 2 (:parent #26)))) #("Guix Configuration as a Channel" 0 31 (:parent #0))) (:export-options (body-only) :back-end #s(org-export-backend :name html :parent nil :transcoders ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :options ((:html-doctype "HTML_DOCTYPE" nil org-html-doctype) (:html-container "HTML_CONTAINER" nil org-html-container-element) (:html-content-class "HTML_CONTENT_CLASS" nil org-html-content-class) (:description "DESCRIPTION" nil nil newline) (:keywords "KEYWORDS" nil nil space) (:html-html5-fancy nil "html5-fancy" org-html-html5-fancy) (:html-link-use-abs-url nil "html-link-use-abs-url" org-html-link-use-abs-url) (:html-link-home "HTML_LINK_HOME" nil org-html-link-home) (:html-link-up "HTML_LINK_UP" nil org-html-link-up) (:html-mathjax "HTML_MATHJAX" nil "" space) (:html-equation-reference-format "HTML_EQUATION_REFERENCE_FORMAT" nil org-html-equation-reference-format t) (:html-postamble nil "html-postamble" org-html-postamble) (:html-preamble nil "html-preamble" org-html-preamble) (:html-head "HTML_HEAD" nil org-html-head newline) (:html-head-extra "HTML_HEAD_EXTRA" nil org-html-head-extra newline) (:subtitle "SUBTITLE" nil nil parse) (:html-head-include-default-style nil "html-style" org-html-head-include-default-style) (:html-head-include-scripts nil "html-scripts" org-html-head-include-scripts) (:html-allow-name-attribute-in-anchors nil nil org-html-allow-name-attribute-in-anchors) (:html-divs nil nil org-html-divs) (:html-checkbox-type nil nil org-html-checkbox-type) (:html-extension nil nil org-html-extension) (:html-footnote-format nil nil org-html-footnote-format) (:html-footnote-separator nil nil org-html-footnote-separator) (:html-footnotes-section nil nil org-html-footnotes-section) (:html-format-drawer-function nil nil org-html-format-drawer-function) (:html-format-headline-function nil nil org-html-format-headline-function) (:html-format-inlinetask-function nil nil org-html-format-inlinetask-function) (:html-home/up-format nil nil org-html-home/up-format) (:html-indent nil nil org-html-indent) (:html-infojs-options nil nil org-html-infojs-options) (:html-infojs-template nil nil org-html-infojs-template) (:html-inline-image-rules nil nil org-html-inline-image-rules) (:html-link-org-files-as-html nil nil org-html-link-org-files-as-html) (:html-mathjax-options nil nil org-html-mathjax-options) (:html-mathjax-template nil nil org-html-mathjax-template) (:html-metadata-timestamp-format nil nil org-html-metadata-timestamp-format) (:html-postamble-format nil nil org-html-postamble-format) (:html-preamble-format nil nil org-html-preamble-format) (:html-prefer-user-labels nil nil org-html-prefer-user-labels) (:html-self-link-headlines nil nil org-html-self-link-headlines) (:html-table-align-individual-fields nil nil org-html-table-align-individual-fields) (:html-table-caption-above nil nil org-html-table-caption-above) (:html-table-data-tags nil nil org-html-table-data-tags) (:html-table-header-tags nil nil org-html-table-header-tags) (:html-table-use-header-tags-for-first-column nil nil org-html-table-use-header-tags-for-first-column) (:html-tag-class-prefix nil nil org-html-tag-class-prefix) (:html-text-markup-alist nil nil org-html-text-markup-alist) (:html-todo-kwd-class-prefix nil nil org-html-todo-kwd-class-prefix) (:html-toplevel-hlevel nil nil org-html-toplevel-hlevel) (:html-use-infojs nil nil org-html-use-infojs) (:html-validation-link nil nil org-html-validation-link) (:html-viewport nil nil org-html-viewport) (:html-inline-images nil nil org-html-inline-images) (:html-table-attributes nil nil org-html-table-default-attributes) (:html-table-row-open-tag nil nil org-html-table-row-open-tag) (:html-table-row-close-tag nil nil org-html-table-row-close-tag) (:html-xml-declaration nil nil org-html-xml-declaration) (:html-wrap-src-lines nil nil org-html-wrap-src-lines) (:html-klipsify-src nil nil org-html-klipsify-src) (:html-klipse-css nil nil org-html-klipse-css) (:html-klipse-js nil nil org-html-klipse-js) (:html-klipse-selection-script nil nil org-html-klipse-selection-script) (:infojs-opt "INFOJS_OPT" nil nil) (:creator "CREATOR" nil org-html-creator-string) (:with-latex nil "tex" org-html-with-latex) (:latex-header "LATEX_HEADER" nil nil newline)) :filters ((:filter-options . org-html-infojs-install-script) (:filter-parse-tree . org-html-image-link-filter) (:filter-final-output . org-html-final-function)) :blocks nil :menu (104 "Export to HTML" ((72 "As HTML buffer" org-html-export-as-html) (104 "As HTML file" org-html-export-to-html) (111 "As HTML file and open" (lambda (a s v b) (if a (org-html-export-to-html t s v b) (org-open-file (org-html-export-to-html nil s v b)))))))) :translate-alist ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data # :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil :html-divs ((preamble "div" "preamble") (content "div" "content") (postamble "div" "postamble")) :html-checkbox-type ascii :html-extension "html" :html-footnote-format "%s" :html-footnote-separator ", " :html-footnotes-section ") :html-format-headline-function org-html-format-headline-default-function :html-format-inlinetask-function org-html-format-inlinetask-default-function :html-home/up-format "" :html-indent nil :html-infojs-options ((path . "https://orgmode.org/org-info.js") (view . "info") (toc . :with-toc) (ftoc . "0") (tdepth . "max") (sdepth . "max") (mouse . "underline") (buttons . "0") (ltoc . "1") (up . :html-link-up) (home . :html-link-home)) :html-infojs-template "\n\n" :html-inline-image-rules (("file" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("http" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("https" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)")) :html-link-org-files-as-html t :html-mathjax-options ((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js") (scale 1.0) (align "center") (font "mathjax-modern") (overflow "overflow") (tags "ams") (indent "0em") (multlinewidth "85%") (tagindent ".8em") (tagside "right")) :html-mathjax-template "\n\n" :html-metadata-timestamp-format "%Y-%m-%d %a %H:%M" :html-postamble-format (("en" " \n" . " ") :html-table-header-tags ("" . " ") :html-table-use-header-tags-for-first-column nil :html-tag-class-prefix "" :html-text-markup-alist ((bold . "%s") (code . "%s") (underline . "%s") (verbatim . "" :html-table-row-close-tag " " :html-xml-declaration (("html" . "") ("php" . "\"; ?>")) :html-wrap-src-lines nil :html-klipsify-src nil :html-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css" :html-klipse-js "https://storage.googleapis.com/app.klipse.tech/plugin_prod/js/klipse_plugin.min.js" :html-klipse-selection-script "window.klipse_settings = {selector_eval_html: '.src-html',\n selector_eval_js: '.src-js',\n selector_eval_python_client: '.src-python',\n selector_eval_scheme: '.src-scheme',\n selector: '.src-clojure',\n selector_eval_ruby: '.src-ruby'};" :infojs-opt nil :creator "Emacs 29.4 (Org mode 9.6.15)" :with-latex t :latex-header "\\usepackage[margin=1.5cm]{geometry}\n\\usepackage{xcolor}\n\\definecolor{link}{HTML}{506060}\n\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :title (#("Setup of a Simple Guix Build Farm and Substitute Server" 0 55 (:parent #148))) :date nil :author (#("Collin J. Doering" 0 17 (:parent #152))) :email "unknown@genenetwork-development" :language "en" :select-tags ("export") :exclude-tags ("noexport") :headline-levels 3 :preserve-breaks nil :section-numbers nil :time-stamp-file t :with-archived-trees headline :with-author t :with-broken-links nil :with-clocks nil :with-creator nil :with-date t :with-drawers (not "LOGBOOK") :with-email nil :with-emphasize t :with-entities t :with-fixed-width t :with-footnotes t :with-inlinetasks t :with-planning nil :with-priority nil :with-properties nil :with-smart-quotes nil :with-special-strings t :with-statistics-cookies t :with-sub-superscript t :with-toc nil :with-tables t :with-tags t :with-tasks t :with-timestamps t :with-title t :with-todo-keywords t :cite-export (basic nil nil) :bibliography nil :filter-body nil :filter-bold nil :filter-babel-call nil :filter-center-block nil :filter-clock nil :filter-code nil :filter-diary-sexp nil :filter-drawer nil :filter-dynamic-block nil :filter-entity nil :filter-example-block nil :filter-export-block nil :filter-export-snippet nil :filter-final-output (org-html-final-function) :filter-fixed-width nil :filter-footnote-definition nil :filter-footnote-reference nil :filter-headline nil :filter-horizontal-rule nil :filter-inline-babel-call nil :filter-inline-src-block nil :filter-inlinetask nil :filter-italic nil :filter-item nil :filter-keyword nil :filter-latex-environment nil :filter-latex-fragment nil :filter-line-break nil :filter-link nil :filter-node-property nil :filter-options (org-html-infojs-install-script) :filter-paragraph nil :filter-parse-tree (org-html-image-link-filter) :filter-plain-list nil :filter-plain-text nil :filter-planning nil :filter-property-drawer nil :filter-quote-block nil :filter-radio-target nil :filter-section nil :filter-special-block nil :filter-src-block nil :filter-statistics-cookie nil :filter-strike-through nil :filter-subscript nil :filter-superscript nil :filter-table nil :filter-table-cell nil :filter-table-row nil :filter-target nil :filter-timestamp nil :filter-underline nil :filter-verbatim nil :filter-verse-block nil :ignore-list nil :parse-tree (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #338) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #341)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #341)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #341) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #354))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #341) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #355))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #341) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #356))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #341) #("Earlier this year " 0 18 (:parent #357)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #357) #("I announced on the guix mailing list" 0 36 (:parent #361))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #357)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #342))) :mode nil :granularity nil :parent #338) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #342) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #345) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #348))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #345) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #352) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #355) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #358) #("Improved Build Diversity" 0 24 (:parent #361)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #355)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #353) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #356) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #359) #("Reduced Latency" 0 15 (:parent #362)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #356)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #354) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #357) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #360) #("Increased Resilience" 0 20 (:parent #363)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #357)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #355) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #358) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #361) #("Community Contribution" 0 22 (:parent #364)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #358))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #345) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #350)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #350) #("here" 0 4 (:parent #354))) #(".\n" 0 2 (:parent #350))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #343))) :mode nil :granularity nil :parent #338) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #343) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #346) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #349))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #346) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #353) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #356) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #359) #("Processor" 0 9 (:parent #362)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #356)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #354) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #357) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #360) #("RAM" 0 3 (:parent #363)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #357)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #355) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #358) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #361) #("Storage" 0 7 (:parent #364)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #358)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #356) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #359) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #362) #("Network" 0 7 (:parent #365)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #359)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #357) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #360) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #363) #("Location" 0 8 (:parent #366)))) #(": Memphis TN\n" 0 13 (:parent #360))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #346) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #351))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #346) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #352))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #346) #("For more details, see the " 0 26 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #353) #("Specifications section" 0 22 (:parent #357))) #("of the Cuirass Manual.\n" 0 23 (:parent #353))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #346) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #354))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #344))) :mode nil :granularity nil :parent #338) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #347))) :mode section :granularity nil :parent #344) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #347) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #350) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #353) #("Guix channels" 0 13 (:parent #357))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #353)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #351))) :mode nil :granularity nil :parent #347) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #351) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #354) #("In order to run Cuirass via the " 0 32 (:parent #357)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #357)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #357)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #357)) #("as a " 0 5 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #357) #("G-Expression" 0 12 (:parent #365))) #("that will return a list of\n" 0 27 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #357) #("cuirass specifications" 0 22 (:parent #367))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #357))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #354)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #354) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #359)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #359)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #359)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #359) #("Cuirass specification" 0 21 (:parent #365))) #("\ndocumentation for more details.\n" 0 33 (:parent #359))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #354) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #360)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #360) #("Guix Configuration as a Channel" 0 31 (:parent #364))) #(".\n" 0 2 (:parent #360))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #352))) :mode nil :granularity nil :parent #347) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #352) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #355) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #358)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #358)) #("field of our " 0 13 (:parent #358)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #358)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #355))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #348))) :mode nil :granularity nil :parent #344) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #348) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #351) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #354)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #354) #("guix publish" 0 12 (:parent #358))) #(", which Guix provides the " 0 26 (:parent #354)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #354) #("guix-publish-service-type" 0 25 (:parent #360))) #(",\nwhich is used in the " 0 23 (:parent #354)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #354)) #("field of " 0 9 (:parent #354)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #354)) #("definition.\n" 0 12 (:parent #354))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #351)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #351) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #356))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #349))) :mode nil :granularity nil :parent #344) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #349) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #352) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #355))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #352) #("To anonymize nginx access logs, the " 0 36 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #356) #("anonip-service-type" 0 19 (:parent #360))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #356)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #356)) #("is defined.\n" 0 12 (:parent #356))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #352) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #352) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #360)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #360)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #352)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #352) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #362)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #362)) #("field of our\n" 0 13 (:parent #362)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #362)) #("declaration.\n" 0 13 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #352)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #350))) :mode nil :granularity nil :parent #344) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #350) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #353) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #356)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #354) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #357) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #360)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #360) #("letsencrypt" 0 11 (:parent #364))) #("via the " 0 8 (:parent #360)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #360) #("certbot" 0 7 (:parent #366))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #360) #("certbox-service-type" 0 20 (:parent #368))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #360)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #360)) #("field in our " 0 13 (:parent #360)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #360)) #("configuration.\n" 0 15 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #357) #("This service references " 0 24 (:parent #362)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #362)) #(", which we define below. It sends " 0 34 (:parent #362)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #362)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #357) #("Next we define a function we will use later in the " 0 51 (:parent #364)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #364) #("Configure Nginx Server Blocks" 0 29 (:parent #368))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #364))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #357)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #355)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #355) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #358) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #358)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #358) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #363))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #358) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #367) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #370)) #("\n" 0 1 (:parent #370))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #367) #(" " 0 2 (:parent #371)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #371)) #("provides a route " 0 17 (:parent #371)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #371)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #371)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #371)) #("command). Given away by the reference to " 0 41 (:parent #371)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #371) #("Nix" 0 3 (:parent #381))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #371)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #371) #("Nix Binary Cache" 0 16 (:parent #383))) #(".\n" 0 2 (:parent #371))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #367) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #372))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #367)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #367) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #374))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #367))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #368) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #371)) #("\n" 0 1 (:parent #371))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #368) #(" " 0 2 (:parent #372)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #372) #("NAR (Nix Archive Format)" 0 24 (:parent #376))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #372)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #372) #("hello" 0 5 (:parent #378))) #("package.\n" 0 9 (:parent #372))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #368) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #368)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #368)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #368) #(" The result is composed of a few parts:\n" 0 41 (:parent #376))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #368) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #380))) :mode item :granularity nil :parent #377) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #380) #("the guix store path\n" 0 20 (:parent #383)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #381))) :mode item :granularity nil :parent #377) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #381) #("a hash uniquely identifying the store item\n" 0 43 (:parent #384)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #382))) :mode item :granularity nil :parent #377) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #382) #("the package-name and version, separated by dashes\n" 0 50 (:parent #385))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #368) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #378)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #378)) #(".\n" 0 2 (:parent #378))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #368))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #369) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #372)) #("\n" 0 1 (:parent #372))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #369) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #373)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #373)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #373)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #373)) #("file.\n" 0 6 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #369)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #369)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #369) #(" If the package is not available, this would return a " 0 55 (:parent #376)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #376)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #376)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #376)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #376)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #376)) #("below.\n" 0 7 (:parent #376))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #369) #(" #+begin" 0 9 (:parent #377)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #377) #("src" 0 3 (:parent #381))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #377)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #377) #("nar" 0 3 (:parent #383))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #377)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #377) #("pass" 0 4 (:parent #385))) #("\" url \";\")\n \"client" 0 25 (:parent #377)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #377) #("body" 0 4 (:parent #387))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #377) #("buffer" 0 6 (:parent #388))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #377) #("size" 0 4 (:parent #389))) #("256k;\"\n" 0 7 (:parent #377)))))))))) :headline-offset 0 :headline-numbering nil :id-alist nil :citations nil :internal-references (("org1d65611" headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #350))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #396))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #442) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #445)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #445)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #445) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #458))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #445) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #459))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #445) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #460))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #445) #("Earlier this year " 0 18 (:parent #461)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #461) #("I announced on the guix mailing list" 0 36 (:parent #465))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #461)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #446))) :mode nil :granularity nil :parent #442) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #446) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #449) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #452))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #449) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #456) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #459) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #462) #("Improved Build Diversity" 0 24 (:parent #465)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #459)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #457) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #460) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #463) #("Reduced Latency" 0 15 (:parent #466)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #460)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #458) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #461) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #464) #("Increased Resilience" 0 20 (:parent #467)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #461)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #459) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #462) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #465) #("Community Contribution" 0 22 (:parent #468)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #462))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #449) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #454)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #454) #("here" 0 4 (:parent #458))) #(".\n" 0 2 (:parent #454))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #447))) :mode nil :granularity nil :parent #442) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #447) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #450) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #453))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #450) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #457) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #460) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #463) #("Processor" 0 9 (:parent #466)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #460)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #458) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #461) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #464) #("RAM" 0 3 (:parent #467)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #461)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #459) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #462) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #465) #("Storage" 0 7 (:parent #468)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #462)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #460) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #463) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #466) #("Network" 0 7 (:parent #469)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #463)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #461) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #464) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #467) #("Location" 0 8 (:parent #470)))) #(": Memphis TN\n" 0 13 (:parent #464))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #450) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #455))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #450) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #456))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #450) #("For more details, see the " 0 26 (:parent #457)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #457) #("Specifications section" 0 22 (:parent #461))) #("of the Cuirass Manual.\n" 0 23 (:parent #457))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #450) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #458))))) #396)) #350 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #400))) :mode nil :granularity nil :parent #396) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #400) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #403) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #406)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #406) #("guix publish" 0 12 (:parent #410))) #(", which Guix provides the " 0 26 (:parent #406)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #406) #("guix-publish-service-type" 0 25 (:parent #412))) #(",\nwhich is used in the " 0 23 (:parent #406)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #406)) #("field of " 0 9 (:parent #406)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #406)) #("definition.\n" 0 12 (:parent #406))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #403)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #403) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #408))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #401))) :mode nil :granularity nil :parent #396) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #401) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #404) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #407))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #404) #("To anonymize nginx access logs, the " 0 36 (:parent #408)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #408) #("anonip-service-type" 0 19 (:parent #412))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #408)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #408)) #("is defined.\n" 0 12 (:parent #408))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #404) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #410))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #404) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #412)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #412)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #404)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #404) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #414)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #414)) #("field of our\n" 0 13 (:parent #414)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #414)) #("declaration.\n" 0 13 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #404)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #402))) :mode nil :granularity nil :parent #396) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #402) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #405) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #408)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #406))) :mode nil :granularity nil :parent #402) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #406) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #409) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #412)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #412) #("letsencrypt" 0 11 (:parent #416))) #("via the " 0 8 (:parent #412)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #412) #("certbot" 0 7 (:parent #418))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #412)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #412) #("certbox-service-type" 0 20 (:parent #420))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #412)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #412)) #("field in our " 0 13 (:parent #412)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #412)) #("configuration.\n" 0 15 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #409) #("This service references " 0 24 (:parent #414)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #414)) #(", which we define below. It sends " 0 34 (:parent #414)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #414)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #409) #("Next we define a function we will use later in the " 0 51 (:parent #416)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #416) #("Configure Nginx Server Blocks" 0 29 (:parent #420))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #416))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #409)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #407)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #407) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #410) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #413))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #410)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #410) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #415))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #419) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #422)) #("\n" 0 1 (:parent #422))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #419) #(" " 0 2 (:parent #423)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #423)) #("provides a route " 0 17 (:parent #423)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #423)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #423)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #423)) #("command). Given away by the reference to " 0 41 (:parent #423)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #423) #("Nix" 0 3 (:parent #433))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #423)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #423) #("Nix Binary Cache" 0 16 (:parent #435))) #(".\n" 0 2 (:parent #423))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #419) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #424))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #419)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #419) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #419))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #420) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #423)) #("\n" 0 1 (:parent #423))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #420) #(" " 0 2 (:parent #424)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #424) #("NAR (Nix Archive Format)" 0 24 (:parent #428))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #424)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #424) #("hello" 0 5 (:parent #430))) #("package.\n" 0 9 (:parent #424))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #420) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #420)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #420)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #420) #(" The result is composed of a few parts:\n" 0 41 (:parent #428))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #420) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #432))) :mode item :granularity nil :parent #429) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #432) #("the guix store path\n" 0 20 (:parent #435)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #433))) :mode item :granularity nil :parent #429) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #433) #("a hash uniquely identifying the store item\n" 0 43 (:parent #436)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #434))) :mode item :granularity nil :parent #429) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #434) #("the package-name and version, separated by dashes\n" 0 50 (:parent #437))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #420) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #430)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #430)) #(".\n" 0 2 (:parent #430))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #420))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #421) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #424)) #("\n" 0 1 (:parent #424))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #421) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #425)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #425)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #425)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #425)) #("file.\n" 0 6 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #421)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #421)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #421) #(" If the package is not available, this would return a " 0 55 (:parent #428)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #428)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #428)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #428)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #428)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #428)) #("below.\n" 0 7 (:parent #428))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #421) #(" #+begin" 0 9 (:parent #429)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #429) #("src" 0 3 (:parent #433))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #429)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #429) #("nar" 0 3 (:parent #435))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #429)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #429) #("pass" 0 4 (:parent #437))) #("\" url \";\")\n \"client" 0 25 (:parent #429)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #429) #("body" 0 4 (:parent #439))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #429) #("buffer" 0 6 (:parent #440))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #429) #("size" 0 4 (:parent #441))) #("256k;\"\n" 0 7 (:parent #429)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #350) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #353) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #356) #("Guix channels" 0 13 (:parent #360))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #356)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #354) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #357) #("In order to run Cuirass via the " 0 32 (:parent #360)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #360)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #360)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #360)) #("as a " 0 5 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #360) #("G-Expression" 0 12 (:parent #368))) #("that will return a list of\n" 0 27 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #360) #("cuirass specifications" 0 22 (:parent #370))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #357)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #357) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #362)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #362)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #362)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #362) #("Cuirass specification" 0 21 (:parent #368))) #("\ndocumentation for more details.\n" 0 33 (:parent #362))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #357) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #363)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #363) #("Guix Configuration as a Channel" 0 31 (:parent #367))) #(".\n" 0 2 (:parent #363))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #355) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #358) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #361)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #361)) #("field of our " 0 13 (:parent #361)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #361)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #358))))) ((other "Cuirass" "-" "Building" "Packages") . 30823953) ((headline "Cuirass" "-" "Building" "Packages") . 30823953) ("org46b8c57" headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #353))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #399) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #402)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #402)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #402) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #415))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #402) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #416))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #402) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #417))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #402) #("Earlier this year " 0 18 (:parent #418)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #418) #("I announced on the guix mailing list" 0 36 (:parent #422))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #418)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #403))) :mode nil :granularity nil :parent #399) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #403) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #406) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #409))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #406) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #413) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #416) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #419) #("Improved Build Diversity" 0 24 (:parent #422)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #416)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #414) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #417) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #420) #("Reduced Latency" 0 15 (:parent #423)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #417)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #415) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #418) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #421) #("Increased Resilience" 0 20 (:parent #424)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #418)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #416) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #419) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #422) #("Community Contribution" 0 22 (:parent #425)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #419))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #406) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #411)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #411) #("here" 0 4 (:parent #415))) #(".\n" 0 2 (:parent #411))))) #353 (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #405))) :mode nil :granularity nil :parent #399) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #408))) :mode section :granularity nil :parent #405) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #408) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #411) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #414)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #414) #("Guix channels" 0 13 (:parent #418))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #414)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #412) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #415) #("In order to run Cuirass via the " 0 32 (:parent #418)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #418)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #418)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #418)) #("as a " 0 5 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #418) #("G-Expression" 0 12 (:parent #426))) #("that will return a list of\n" 0 27 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #418) #("cuirass specifications" 0 22 (:parent #428))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #415)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #415) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #420)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #420)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #420) #("Cuirass specification" 0 21 (:parent #426))) #("\ndocumentation for more details.\n" 0 33 (:parent #420))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #415) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #421)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #421) #("Guix Configuration as a Channel" 0 31 (:parent #425))) #(".\n" 0 2 (:parent #421))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #413) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #416) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #419)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #419)) #("field of our " 0 13 (:parent #419)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #419)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #416))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #409))) :mode nil :granularity nil :parent #405) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #409) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #412) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #415)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #415) #("guix publish" 0 12 (:parent #419))) #(", which Guix provides the " 0 26 (:parent #415)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #415) #("guix-publish-service-type" 0 25 (:parent #421))) #(",\nwhich is used in the " 0 23 (:parent #415)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #415)) #("field of " 0 9 (:parent #415)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #415)) #("definition.\n" 0 12 (:parent #415))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #412)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #412) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #417))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #410))) :mode nil :granularity nil :parent #405) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #410) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #413) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #416))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #413) #("To anonymize nginx access logs, the " 0 36 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #417) #("anonip-service-type" 0 19 (:parent #421))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #417)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #417)) #("is defined.\n" 0 12 (:parent #417))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #413) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #413) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #421)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #421)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #413)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #413) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #423)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #423)) #("field of our\n" 0 13 (:parent #423)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #423)) #("declaration.\n" 0 13 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #413)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #411))) :mode nil :granularity nil :parent #405) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #411) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #414) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #417)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #415) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #418) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #421)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #421) #("letsencrypt" 0 11 (:parent #425))) #("via the " 0 8 (:parent #421)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #421) #("certbot" 0 7 (:parent #427))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #421) #("certbox-service-type" 0 20 (:parent #429))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #421)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #421)) #("field in our " 0 13 (:parent #421)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #421)) #("configuration.\n" 0 15 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #418) #("This service references " 0 24 (:parent #423)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #423)) #(", which we define below. It sends " 0 34 (:parent #423)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #423)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #418) #("Next we define a function we will use later in the " 0 51 (:parent #425)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #425) #("Configure Nginx Server Blocks" 0 29 (:parent #429))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #418)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #416)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #416) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #419) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #419)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #419) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #424))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #419) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #428) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #431)) #("\n" 0 1 (:parent #431))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #428) #(" " 0 2 (:parent #432)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #432)) #("provides a route " 0 17 (:parent #432)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #432)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #432)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #432)) #("command). Given away by the reference to " 0 41 (:parent #432)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #432) #("Nix" 0 3 (:parent #442))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #432)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #432) #("Nix Binary Cache" 0 16 (:parent #444))) #(".\n" 0 2 (:parent #432))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #428) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #433))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #428)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #428) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #435))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #428))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #429) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #432)) #("\n" 0 1 (:parent #432))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #429) #(" " 0 2 (:parent #433)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #433) #("NAR (Nix Archive Format)" 0 24 (:parent #437))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #433)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #433) #("hello" 0 5 (:parent #439))) #("package.\n" 0 9 (:parent #433))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #429) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #429)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #429)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #429) #(" The result is composed of a few parts:\n" 0 41 (:parent #437))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #429) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #441))) :mode item :granularity nil :parent #438) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #441) #("the guix store path\n" 0 20 (:parent #444)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #442))) :mode item :granularity nil :parent #438) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #442) #("a hash uniquely identifying the store item\n" 0 43 (:parent #445)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #443))) :mode item :granularity nil :parent #438) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #443) #("the package-name and version, separated by dashes\n" 0 50 (:parent #446))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #429) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #439)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #439)) #(".\n" 0 2 (:parent #439))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #429))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #430) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #433)) #("\n" 0 1 (:parent #433))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #430) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #434)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #434)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #434)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #434)) #("file.\n" 0 6 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #430)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #430)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #430) #(" If the package is not available, this would return a " 0 55 (:parent #437)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #437)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #437)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #437)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #437)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #437)) #("below.\n" 0 7 (:parent #437))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #430) #(" #+begin" 0 9 (:parent #438)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #438) #("src" 0 3 (:parent #442))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #438)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #438) #("nar" 0 3 (:parent #444))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #438)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #438) #("pass" 0 4 (:parent #446))) #("\" url \";\")\n \"client" 0 25 (:parent #438)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #438) #("body" 0 4 (:parent #448))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #438) #("buffer" 0 6 (:parent #449))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #438) #("size" 0 4 (:parent #450))) #("256k;\"\n" 0 7 (:parent #438))))))))))) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #353) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #356) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #359))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #356) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #363) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #366) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #369) #("Processor" 0 9 (:parent #372)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #366)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #364) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #367) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #370) #("RAM" 0 3 (:parent #373)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #367)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #365) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #368) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #371) #("Storage" 0 7 (:parent #374)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #368)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #366) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #369) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #372) #("Network" 0 7 (:parent #375)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #369)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #367) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #370) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #373) #("Location" 0 8 (:parent #376)))) #(": Memphis TN\n" 0 13 (:parent #370))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #356) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #361))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #356) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #362))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #356) #("For more details, see the " 0 26 (:parent #363)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #363) #("Specifications section" 0 22 (:parent #367))) #("of the Cuirass Manual.\n" 0 23 (:parent #363))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #356) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #364))))) ((other "Hardware" "and" "Infrastructure") . 74157143) ((headline "Hardware" "and" "Infrastructure") . 74157143) ("orgcc40a3d" headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #356))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #402) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #405)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #405)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #405) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #418))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #405) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #419))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #405) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #420))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #405) #("Earlier this year " 0 18 (:parent #421)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #421) #("I announced on the guix mailing list" 0 36 (:parent #425))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #421)))) #356 (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #407) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #410) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #413))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #417) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #420) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #423) #("Processor" 0 9 (:parent #426)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #420)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #418) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #421) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #424) #("RAM" 0 3 (:parent #427)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #421)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #419) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #422) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #425) #("Storage" 0 7 (:parent #428)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #422)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #420) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #423) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #426) #("Network" 0 7 (:parent #429)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #423)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #421) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #424) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #427) #("Location" 0 8 (:parent #430)))) #(": Memphis TN\n" 0 13 (:parent #424))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #410) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #415))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #410) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #416))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #410) #("For more details, see the " 0 26 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #417) #("Specifications section" 0 22 (:parent #421))) #("of the Cuirass Manual.\n" 0 23 (:parent #417))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #410) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #418))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #408))) :mode nil :granularity nil :parent #402) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #411))) :mode section :granularity nil :parent #408) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #411) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #414) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #417) #("Guix channels" 0 13 (:parent #421))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #417)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #415) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #418) #("In order to run Cuirass via the " 0 32 (:parent #421)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #421)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #421)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #421)) #("as a " 0 5 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #421) #("G-Expression" 0 12 (:parent #429))) #("that will return a list of\n" 0 27 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #421) #("cuirass specifications" 0 22 (:parent #431))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #418)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #418) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #423)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #423)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #423)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #423) #("Cuirass specification" 0 21 (:parent #429))) #("\ndocumentation for more details.\n" 0 33 (:parent #423))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #418) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #424)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #424) #("Guix Configuration as a Channel" 0 31 (:parent #428))) #(".\n" 0 2 (:parent #424))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #416) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #419) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #422)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #422)) #("field of our " 0 13 (:parent #422)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #422)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #419))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #412) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #415) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #418) #("guix publish" 0 12 (:parent #422))) #(", which Guix provides the " 0 26 (:parent #418)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #418) #("guix-publish-service-type" 0 25 (:parent #424))) #(",\nwhich is used in the " 0 23 (:parent #418)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #418)) #("field of " 0 9 (:parent #418)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #418)) #("definition.\n" 0 12 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #415)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #415) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #420))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #413) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #416) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #419))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #416) #("To anonymize nginx access logs, the " 0 36 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #420) #("anonip-service-type" 0 19 (:parent #424))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #420)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #420)) #("is defined.\n" 0 12 (:parent #420))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #416) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #416) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #424)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #424)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #416)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #416) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #426)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #426)) #("field of our\n" 0 13 (:parent #426)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #426)) #("declaration.\n" 0 13 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #416)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #414))) :mode nil :granularity nil :parent #408) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #414) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #417) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #420)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #418))) :mode nil :granularity nil :parent #414) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #418) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #421) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #424)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #424) #("letsencrypt" 0 11 (:parent #428))) #("via the " 0 8 (:parent #424)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #424) #("certbot" 0 7 (:parent #430))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #424)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #424) #("certbox-service-type" 0 20 (:parent #432))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #424)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #424)) #("field in our " 0 13 (:parent #424)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #424)) #("configuration.\n" 0 15 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #421) #("This service references " 0 24 (:parent #426)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #426)) #(", which we define below. It sends " 0 34 (:parent #426)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #426)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #421) #("Next we define a function we will use later in the " 0 51 (:parent #428)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #428) #("Configure Nginx Server Blocks" 0 29 (:parent #432))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #428))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #421)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #419)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #419))) :mode nil :granularity nil :parent #414) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #419) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #422) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #422)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #422) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #427))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #422) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #431) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #434)) #("\n" 0 1 (:parent #434))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #431) #(" " 0 2 (:parent #435)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #435)) #("provides a route " 0 17 (:parent #435)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #435)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #435)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #435)) #("command). Given away by the reference to " 0 41 (:parent #435)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #435) #("Nix" 0 3 (:parent #445))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #435)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #435) #("Nix Binary Cache" 0 16 (:parent #447))) #(".\n" 0 2 (:parent #435))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #431) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #436))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #431)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #431) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #438))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #431))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #432) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #435)) #("\n" 0 1 (:parent #435))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #432) #(" " 0 2 (:parent #436)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #436) #("NAR (Nix Archive Format)" 0 24 (:parent #440))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #436)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #436) #("hello" 0 5 (:parent #442))) #("package.\n" 0 9 (:parent #436))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #432) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #432)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #432)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #432) #(" The result is composed of a few parts:\n" 0 41 (:parent #440))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #432) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #444))) :mode item :granularity nil :parent #441) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #444) #("the guix store path\n" 0 20 (:parent #447)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #445))) :mode item :granularity nil :parent #441) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #445) #("a hash uniquely identifying the store item\n" 0 43 (:parent #448)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #446))) :mode item :granularity nil :parent #441) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #446) #("the package-name and version, separated by dashes\n" 0 50 (:parent #449))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #432) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #442)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #442)) #(".\n" 0 2 (:parent #442))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #432))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #433) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #436)) #("\n" 0 1 (:parent #436))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #433) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #437)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #437)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #437)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #437)) #("file.\n" 0 6 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #433)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #433)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #433) #(" If the package is not available, this would return a " 0 55 (:parent #440)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #440)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #440)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #440)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #440)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #440)) #("below.\n" 0 7 (:parent #440))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #433) #(" #+begin" 0 9 (:parent #441)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #441) #("src" 0 3 (:parent #445))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #441)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #441) #("nar" 0 3 (:parent #447))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #441)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #441) #("pass" 0 4 (:parent #449))) #("\" url \";\")\n \"client" 0 25 (:parent #441)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #441) #("body" 0 4 (:parent #451))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #441) #("buffer" 0 6 (:parent #452))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #441) #("size" 0 4 (:parent #453))) #("256k;\"\n" 0 7 (:parent #441))))))))))) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #356) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #359) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #362))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #359) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #366) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #369) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #372) #("Improved Build Diversity" 0 24 (:parent #375)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #369)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #367) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #370) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #373) #("Reduced Latency" 0 15 (:parent #376)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #370)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #368) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #371) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #374) #("Increased Resilience" 0 20 (:parent #377)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #371)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #369) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #372) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #375) #("Community Contribution" 0 22 (:parent #378)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #372))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #359) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #364)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #364) #("here" 0 4 (:parent #368))) #(".\n" 0 2 (:parent #364))))) ((other "Why" "Build" "Another" "Substitute" "Server?") . 214174269) ((headline "Why" "Build" "Another" "Substitute" "Server?") . 214174269)) :resolve-fuzzy-link-cache #))
#f(compiled-function (element) #)((link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #70))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #116))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #162))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #208) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #211)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #211)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #211)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #211) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #224))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #211) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #225))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #211) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #226))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #211) #("Earlier this year " 0 18 (:parent #227)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #227) #("I announced on the guix mailing list" 0 36 (:parent #231))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #227)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #212))) :mode nil :granularity nil :parent #208) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #212) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #215) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #218))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #215) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #219) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #222) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #225) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #228) #("Improved Build Diversity" 0 24 (:parent #231)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #225)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #219) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #223) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #226) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #229) #("Reduced Latency" 0 15 (:parent #232)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #226)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #219) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #224) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #227) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #230) #("Increased Resilience" 0 20 (:parent #233)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #227)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #219) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #225) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #228) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #231) #("Community Contribution" 0 22 (:parent #234)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #228))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #215) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #220)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #220) #("here" 0 4 (:parent #224))) #(".\n" 0 2 (:parent #220))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #213))) :mode nil :granularity nil :parent #208) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #213) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #216) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #219))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #216) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #223) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #226) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #229) #("Processor" 0 9 (:parent #232)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #226)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #224) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #227) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #230) #("RAM" 0 3 (:parent #233)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #227)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #225) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #228) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #231) #("Storage" 0 7 (:parent #234)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #228)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #226) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #229) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #232) #("Network" 0 7 (:parent #235)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #229)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #220) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #227) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #230) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #233) #("Location" 0 8 (:parent #236)))) #(": Memphis TN\n" 0 13 (:parent #230))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #216) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #221))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #216) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #222))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #216) #("For more details, see the " 0 26 (:parent #223)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #223) #("Specifications section" 0 22 (:parent #227))) #("of the Cuirass Manual.\n" 0 23 (:parent #223))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #216) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #224))))) #162)) #116 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #166))) :mode nil :granularity nil :parent #162) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #166) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #169) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #172)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #172) #("guix publish" 0 12 (:parent #176))) #(", which Guix provides the " 0 26 (:parent #172)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #172) #("guix-publish-service-type" 0 25 (:parent #178))) #(",\nwhich is used in the " 0 23 (:parent #172)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #172)) #("field of " 0 9 (:parent #172)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #172)) #("definition.\n" 0 12 (:parent #172))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #169)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #169) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #174))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #167))) :mode nil :granularity nil :parent #162) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #167) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #170) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #173))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #170) #("To anonymize nginx access logs, the " 0 36 (:parent #174)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #174) #("anonip-service-type" 0 19 (:parent #178))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #174)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #174)) #("is defined.\n" 0 12 (:parent #174))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #170)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #170) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #176))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #170)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #170) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #178)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #178)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #178))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #170)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #170) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #180)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #180)) #("field of our\n" 0 13 (:parent #180)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #180)) #("declaration.\n" 0 13 (:parent #180))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #170)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #168))) :mode nil :granularity nil :parent #162) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #168) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #171) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #174)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #172))) :mode nil :granularity nil :parent #168) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #172) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #175) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #178)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #178) #("letsencrypt" 0 11 (:parent #182))) #("via the " 0 8 (:parent #178)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #178) #("certbot" 0 7 (:parent #184))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #178)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #178) #("certbox-service-type" 0 20 (:parent #186))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #178)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #178)) #("field in our " 0 13 (:parent #178)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #178)) #("configuration.\n" 0 15 (:parent #178))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #175)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #175) #("This service references " 0 24 (:parent #180)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #180)) #(", which we define below. It sends " 0 34 (:parent #180)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #180)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #180))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #175)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #175) #("Next we define a function we will use later in the " 0 51 (:parent #182)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #182) #("Configure Nginx Server Blocks" 0 29 (:parent #186))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #182))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #175)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #173)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #173))) :mode nil :granularity nil :parent #168) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #173) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #176) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #179))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #176)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #176) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #181))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #176) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #182) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #185) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #188)) #("\n" 0 1 (:parent #188))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #185) #(" " 0 2 (:parent #189)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #189)) #("provides a route " 0 17 (:parent #189)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #189)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #189)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #189)) #("command). Given away by the reference to " 0 41 (:parent #189)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #189) #("Nix" 0 3 (:parent #199))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #189)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #189) #("Nix Binary Cache" 0 16 (:parent #201))) #(".\n" 0 2 (:parent #189))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #185) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #190))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #185)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #185) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #192))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #185))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #182) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #186) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #189)) #("\n" 0 1 (:parent #189))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #186) #(" " 0 2 (:parent #190)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #190) #("NAR (Nix Archive Format)" 0 24 (:parent #194))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #190)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #190) #("hello" 0 5 (:parent #196))) #("package.\n" 0 9 (:parent #190))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #186) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #191))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #186)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #186)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #186) #(" The result is composed of a few parts:\n" 0 41 (:parent #194))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #186) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #198))) :mode item :granularity nil :parent #195) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #198) #("the guix store path\n" 0 20 (:parent #201)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #199))) :mode item :granularity nil :parent #195) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #199) #("a hash uniquely identifying the store item\n" 0 43 (:parent #202)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #200))) :mode item :granularity nil :parent #195) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #200) #("the package-name and version, separated by dashes\n" 0 50 (:parent #203))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #186) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #196)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #196)) #(".\n" 0 2 (:parent #196))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #186))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #182) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #187) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #190)) #("\n" 0 1 (:parent #190))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #187) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #191)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #191)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #191)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #191)) #("file.\n" 0 6 (:parent #191))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #187)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #187)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #187) #(" If the package is not available, this would return a " 0 55 (:parent #194)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #194)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #194)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #194)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #194)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #194)) #("below.\n" 0 7 (:parent #194))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #187) #(" #+begin" 0 9 (:parent #195)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #195) #("src" 0 3 (:parent #199))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #195)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #195) #("nar" 0 3 (:parent #201))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #195)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #195) #("pass" 0 4 (:parent #203))) #("\" url \";\")\n \"client" 0 25 (:parent #195)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #195) #("body" 0 4 (:parent #205))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #195) #("buffer" 0 6 (:parent #206))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #195) #("size" 0 4 (:parent #207))) #("256k;\"\n" 0 7 (:parent #195)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #116) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #119) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #122)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #122) #("Guix channels" 0 13 (:parent #126))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #122)))) #70 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #121))) :mode nil :granularity nil :parent #116) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #121) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #124) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #127)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #127)) #("field of our " 0 13 (:parent #127)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #127)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #127))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #124)))))) #46)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #46) #("In order to run Cuirass via the " 0 32 (:parent #49)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #49)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #49)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #49)) #("as a " 0 5 (:parent #49)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #49) #("G-Expression" 0 12 (:parent #57))) #("that will return a list of\n" 0 27 (:parent #49)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #49) #("cuirass specifications" 0 22 (:parent #59))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #49))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #46)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #46) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #51)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #51)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #51)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #51) #("Cuirass specification" 0 21 (:parent #57))) #("\ndocumentation for more details.\n" 0 33 (:parent #51))) #26)) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #26)) #0 #(".\n" 0 2 (:parent #26)))) #("Guix Configuration as a Channel" 0 31 (:parent #0))))
mapconcat(#f(compiled-function (element) #) (#("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #48))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #94))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #140))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #186) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #189)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #189)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #189) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #202))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #189) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #203))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #189) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #204))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #189) #("Earlier this year " 0 18 (:parent #205)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #205) #("I announced on the guix mailing list" 0 36 (:parent #209))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #205)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #190))) :mode nil :granularity nil :parent #186) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #190) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #193) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #196))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #193) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #200) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #203) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #206) #("Improved Build Diversity" 0 24 (:parent #209)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #203)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #201) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #204) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #207) #("Reduced Latency" 0 15 (:parent #210)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #204)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #202) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #205) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #208) #("Increased Resilience" 0 20 (:parent #211)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #205)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #203) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #206) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #209) #("Community Contribution" 0 22 (:parent #212)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #206))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #193) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #198)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #198) #("here" 0 4 (:parent #202))) #(".\n" 0 2 (:parent #198))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #191))) :mode nil :granularity nil :parent #186) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #191) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #194) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #197))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #194) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #201) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #204) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #207) #("Processor" 0 9 (:parent #210)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #204)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #202) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #205) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #208) #("RAM" 0 3 (:parent #211)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #205)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #203) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #206) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #209) #("Storage" 0 7 (:parent #212)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #206)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #204) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #207) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #210) #("Network" 0 7 (:parent #213)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #207)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #205) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #208) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #211) #("Location" 0 8 (:parent #214)))) #(": Memphis TN\n" 0 13 (:parent #208))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #194) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #199))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #194) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #200))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #194) #("For more details, see the " 0 26 (:parent #201)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #201) #("Specifications section" 0 22 (:parent #205))) #("of the Cuirass Manual.\n" 0 23 (:parent #201))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #194) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #202))))) #140)) #94 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #144))) :mode nil :granularity nil :parent #140) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #144) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #147) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #150)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #150) #("guix publish" 0 12 (:parent #154))) #(", which Guix provides the " 0 26 (:parent #150)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #150) #("guix-publish-service-type" 0 25 (:parent #156))) #(",\nwhich is used in the " 0 23 (:parent #150)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #150)) #("field of " 0 9 (:parent #150)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #150)) #("definition.\n" 0 12 (:parent #150))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #147)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #147) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #152))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #145))) :mode nil :granularity nil :parent #140) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #145) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #148) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #151))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #148) #("To anonymize nginx access logs, the " 0 36 (:parent #152)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #152) #("anonip-service-type" 0 19 (:parent #156))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #152)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #152)) #("is defined.\n" 0 12 (:parent #152))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #148)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #148) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #154))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #148)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #148) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #156)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #156)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #156))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #148)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #148) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #158)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #158)) #("field of our\n" 0 13 (:parent #158)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #158)) #("declaration.\n" 0 13 (:parent #158))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #148)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #146))) :mode nil :granularity nil :parent #140) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #146) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #149) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #152)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #150))) :mode nil :granularity nil :parent #146) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #150) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #153) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #156)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #156) #("letsencrypt" 0 11 (:parent #160))) #("via the " 0 8 (:parent #156)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #156) #("certbot" 0 7 (:parent #162))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #156)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #156) #("certbox-service-type" 0 20 (:parent #164))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #156)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #156)) #("field in our " 0 13 (:parent #156)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #156)) #("configuration.\n" 0 15 (:parent #156))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #153)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #153) #("This service references " 0 24 (:parent #158)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #158)) #(", which we define below. It sends " 0 34 (:parent #158)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #158)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #158))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #153)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #153) #("Next we define a function we will use later in the " 0 51 (:parent #160)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #160) #("Configure Nginx Server Blocks" 0 29 (:parent #164))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #160))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #153)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #151)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #151))) :mode nil :granularity nil :parent #146) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #151) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #154) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #157))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #154)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #154) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #159))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #154) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #160) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #163) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #166)) #("\n" 0 1 (:parent #166))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #163) #(" " 0 2 (:parent #167)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #167)) #("provides a route " 0 17 (:parent #167)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #167)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #167)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #167)) #("command). Given away by the reference to " 0 41 (:parent #167)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #167) #("Nix" 0 3 (:parent #177))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #167)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #167) #("Nix Binary Cache" 0 16 (:parent #179))) #(".\n" 0 2 (:parent #167))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #163) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #168))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #163)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #163) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #170))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #163))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #160) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #164) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #167)) #("\n" 0 1 (:parent #167))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #164) #(" " 0 2 (:parent #168)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #168) #("NAR (Nix Archive Format)" 0 24 (:parent #172))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #168)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #168) #("hello" 0 5 (:parent #174))) #("package.\n" 0 9 (:parent #168))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #164) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #169))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #164)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #164)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #164) #(" The result is composed of a few parts:\n" 0 41 (:parent #172))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #164) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #176))) :mode item :granularity nil :parent #173) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #176) #("the guix store path\n" 0 20 (:parent #179)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #177))) :mode item :granularity nil :parent #173) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #177) #("a hash uniquely identifying the store item\n" 0 43 (:parent #180)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #178))) :mode item :granularity nil :parent #173) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #178) #("the package-name and version, separated by dashes\n" 0 50 (:parent #181))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #164) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #174)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #174)) #(".\n" 0 2 (:parent #174))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #164))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #160) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #165) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #168)) #("\n" 0 1 (:parent #168))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #165) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #169)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #169)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #169)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #169)) #("file.\n" 0 6 (:parent #169))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #165)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #165)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #165) #(" If the package is not available, this would return a " 0 55 (:parent #172)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #172)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #172)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #172)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #172)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #172)) #("below.\n" 0 7 (:parent #172))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #165) #(" #+begin" 0 9 (:parent #173)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #173) #("src" 0 3 (:parent #177))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #173)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #173) #("nar" 0 3 (:parent #179))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #173)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #173) #("pass" 0 4 (:parent #181))) #("\" url \";\")\n \"client" 0 25 (:parent #173)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #173) #("body" 0 4 (:parent #183))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #173) #("buffer" 0 6 (:parent #184))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #173) #("size" 0 4 (:parent #185))) #("256k;\"\n" 0 7 (:parent #173)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #94) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #97) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #100)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #100) #("Guix channels" 0 13 (:parent #104))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #100)))) #48 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #99))) :mode nil :granularity nil :parent #94) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #99) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #102) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #105)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #105)) #("field of our " 0 13 (:parent #105)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #105)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #105))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #102)))))) #24)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #24) #("In order to run Cuirass via the " 0 32 (:parent #27)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #27)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #27)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #27)) #("as a " 0 5 (:parent #27)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #27) #("G-Expression" 0 12 (:parent #35))) #("that will return a list of\n" 0 27 (:parent #27)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #27) #("cuirass specifications" 0 22 (:parent #37))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #27))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #24)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #24) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #29)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #29)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #29)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #29) #("Cuirass specification" 0 21 (:parent #35))) #("\ndocumentation for more details.\n" 0 33 (:parent #29))) #4)) . #0))) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #72))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #118))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #164))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #210) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #213)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #213)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #213)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #213)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #213)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #213)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #213)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #213)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #213)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #213)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #213) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #226))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #213) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #227))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #213) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #228))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #213) #("Earlier this year " 0 18 (:parent #229)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #229) #("I announced on the guix mailing list" 0 36 (:parent #233))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #229)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #214))) :mode nil :granularity nil :parent #210) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #214) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #217) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #220))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #217) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #221) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #224) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #227) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #230) #("Improved Build Diversity" 0 24 (:parent #233)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #227)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #221) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #225) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #228) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #231) #("Reduced Latency" 0 15 (:parent #234)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #228)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #221) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #226) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #229) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #232) #("Increased Resilience" 0 20 (:parent #235)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #229)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #221) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #227) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #230) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #233) #("Community Contribution" 0 22 (:parent #236)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #230))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #217) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #222)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #222) #("here" 0 4 (:parent #226))) #(".\n" 0 2 (:parent #222))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #215))) :mode nil :granularity nil :parent #210) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #215) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #218) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #221))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #218) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #222) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #225) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #228) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #231) #("Processor" 0 9 (:parent #234)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #228)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #222) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #226) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #229) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #232) #("RAM" 0 3 (:parent #235)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #229)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #222) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #227) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #230) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #233) #("Storage" 0 7 (:parent #236)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #230)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #222) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #228) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #231) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #234) #("Network" 0 7 (:parent #237)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #231)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #222) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #229) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #232) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #235) #("Location" 0 8 (:parent #238)))) #(": Memphis TN\n" 0 13 (:parent #232))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #218) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #223))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #218) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #224))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #218) #("For more details, see the " 0 26 (:parent #225)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #225) #("Specifications section" 0 22 (:parent #229))) #("of the Cuirass Manual.\n" 0 23 (:parent #225))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #218) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #226))))) #164)) #118 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #168))) :mode nil :granularity nil :parent #164) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #168) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #171) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #174)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #174) #("guix publish" 0 12 (:parent #178))) #(", which Guix provides the " 0 26 (:parent #174)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #174) #("guix-publish-service-type" 0 25 (:parent #180))) #(",\nwhich is used in the " 0 23 (:parent #174)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #174)) #("field of " 0 9 (:parent #174)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #174)) #("definition.\n" 0 12 (:parent #174))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #171)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #171) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #176))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #169))) :mode nil :granularity nil :parent #164) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #169) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #172) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #175))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #172) #("To anonymize nginx access logs, the " 0 36 (:parent #176)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #176) #("anonip-service-type" 0 19 (:parent #180))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #176)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #176)) #("is defined.\n" 0 12 (:parent #176))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #172)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #172) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #178))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #172)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #172) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #180)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #180)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #180))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #172)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #172) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #182)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #182)) #("field of our\n" 0 13 (:parent #182)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #182)) #("declaration.\n" 0 13 (:parent #182))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #172)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #170))) :mode nil :granularity nil :parent #164) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #170) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #173) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #176)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #174))) :mode nil :granularity nil :parent #170) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #174) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #177) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #180)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #180) #("letsencrypt" 0 11 (:parent #184))) #("via the " 0 8 (:parent #180)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #180) #("certbot" 0 7 (:parent #186))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #180)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #180) #("certbox-service-type" 0 20 (:parent #188))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #180)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #180)) #("field in our " 0 13 (:parent #180)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #180)) #("configuration.\n" 0 15 (:parent #180))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #177)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #177) #("This service references " 0 24 (:parent #182)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #182)) #(", which we define below. It sends " 0 34 (:parent #182)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #182)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #182))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #177)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #177) #("Next we define a function we will use later in the " 0 51 (:parent #184)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #184) #("Configure Nginx Server Blocks" 0 29 (:parent #188))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #184))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #177)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #175)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #175))) :mode nil :granularity nil :parent #170) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #175) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #178) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #181))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #178)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #178) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #183))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #178) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #184) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #187) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #190)) #("\n" 0 1 (:parent #190))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #187) #(" " 0 2 (:parent #191)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #191)) #("provides a route " 0 17 (:parent #191)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #191)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #191)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #191)) #("command). Given away by the reference to " 0 41 (:parent #191)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #191) #("Nix" 0 3 (:parent #201))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #191)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #191) #("Nix Binary Cache" 0 16 (:parent #203))) #(".\n" 0 2 (:parent #191))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #187) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #192))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #187)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #187) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #194))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #187))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #184) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #188) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #191)) #("\n" 0 1 (:parent #191))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #188) #(" " 0 2 (:parent #192)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #192) #("NAR (Nix Archive Format)" 0 24 (:parent #196))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #192)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #192) #("hello" 0 5 (:parent #198))) #("package.\n" 0 9 (:parent #192))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #188) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #193))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #188)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #188)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #188) #(" The result is composed of a few parts:\n" 0 41 (:parent #196))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #188) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #200))) :mode item :granularity nil :parent #197) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #200) #("the guix store path\n" 0 20 (:parent #203)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #201))) :mode item :granularity nil :parent #197) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #201) #("a hash uniquely identifying the store item\n" 0 43 (:parent #204)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #202))) :mode item :granularity nil :parent #197) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #202) #("the package-name and version, separated by dashes\n" 0 50 (:parent #205))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #188) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #198)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #198)) #(".\n" 0 2 (:parent #198))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #188))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #184) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #189) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #192)) #("\n" 0 1 (:parent #192))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #189) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #193)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #193)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #193)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #193)) #("file.\n" 0 6 (:parent #193))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #189)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #189)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #189) #(" If the package is not available, this would return a " 0 55 (:parent #196)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #196)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #196)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #196)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #196)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #196)) #("below.\n" 0 7 (:parent #196))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #189) #(" #+begin" 0 9 (:parent #197)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #197) #("src" 0 3 (:parent #201))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #197)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #197) #("nar" 0 3 (:parent #203))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #197)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #197) #("pass" 0 4 (:parent #205))) #("\" url \";\")\n \"client" 0 25 (:parent #197)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #197) #("body" 0 4 (:parent #207))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #197) #("buffer" 0 6 (:parent #208))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #197) #("size" 0 4 (:parent #209))) #("256k;\"\n" 0 7 (:parent #197)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #118) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #121) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #124)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #124) #("Guix channels" 0 13 (:parent #128))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #124)))) #72 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #123))) :mode nil :granularity nil :parent #118) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #123) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #126) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #129)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #129)) #("field of our " 0 13 (:parent #129)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #129)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #129))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #126)))))) #48)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #48) #("In order to run Cuirass via the " 0 32 (:parent #51)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #51)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #51)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #51)) #("as a " 0 5 (:parent #51)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #51) #("G-Expression" 0 12 (:parent #59))) #("that will return a list of\n" 0 27 (:parent #51)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #51) #("cuirass specifications" 0 22 (:parent #61))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #51))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #48)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #48) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #53)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #53)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #53)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #53) #("Cuirass specification" 0 21 (:parent #59))) #("\ndocumentation for more details.\n" 0 33 (:parent #53))) #28)) . #0)) #("Guix Configuration as a Channel" 0 31 (:parent #2))) #(".\n" 0 2 (:parent (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #50))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #96))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #142))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #188) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #191)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #191)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #191)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #191)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #191)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #191)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #191)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #191)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #191)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #191)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #191) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #204))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #191) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #205))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #191) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #206))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #191) #("Earlier this year " 0 18 (:parent #207)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #207) #("I announced on the guix mailing list" 0 36 (:parent #211))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #207)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #192))) :mode nil :granularity nil :parent #188) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #192) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #195) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #198))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #195) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #199) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #202) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #205) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #208) #("Improved Build Diversity" 0 24 (:parent #211)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #205)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #199) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #203) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #206) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #209) #("Reduced Latency" 0 15 (:parent #212)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #206)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #199) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #204) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #207) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #210) #("Increased Resilience" 0 20 (:parent #213)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #207)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #199) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #205) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #208) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #211) #("Community Contribution" 0 22 (:parent #214)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #208))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #195) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #200)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #200) #("here" 0 4 (:parent #204))) #(".\n" 0 2 (:parent #200))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #193))) :mode nil :granularity nil :parent #188) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #193) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #196) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #199))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #196) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #200) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #203) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #206) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #209) #("Processor" 0 9 (:parent #212)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #206)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #200) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #204) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #207) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #210) #("RAM" 0 3 (:parent #213)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #207)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #200) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #205) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #208) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #211) #("Storage" 0 7 (:parent #214)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #208)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #200) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #206) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #209) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #212) #("Network" 0 7 (:parent #215)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #209)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #200) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #207) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #210) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #213) #("Location" 0 8 (:parent #216)))) #(": Memphis TN\n" 0 13 (:parent #210))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #196) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #201))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #196) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #202))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #196) #("For more details, see the " 0 26 (:parent #203)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #203) #("Specifications section" 0 22 (:parent #207))) #("of the Cuirass Manual.\n" 0 23 (:parent #203))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #196) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #204))))) #142)) #96 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #146))) :mode nil :granularity nil :parent #142) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #146) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #149) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #152)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #152) #("guix publish" 0 12 (:parent #156))) #(", which Guix provides the " 0 26 (:parent #152)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #152) #("guix-publish-service-type" 0 25 (:parent #158))) #(",\nwhich is used in the " 0 23 (:parent #152)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #152)) #("field of " 0 9 (:parent #152)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #152)) #("definition.\n" 0 12 (:parent #152))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #149)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #149) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #154))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #147))) :mode nil :granularity nil :parent #142) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #147) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #150) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #153))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #150) #("To anonymize nginx access logs, the " 0 36 (:parent #154)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #154) #("anonip-service-type" 0 19 (:parent #158))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #154)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #154)) #("is defined.\n" 0 12 (:parent #154))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #150)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #150) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #156))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #150)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #150) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #158)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #158)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #158))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #150)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #150) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #160)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #160)) #("field of our\n" 0 13 (:parent #160)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #160)) #("declaration.\n" 0 13 (:parent #160))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #150)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #148))) :mode nil :granularity nil :parent #142) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #148) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #151) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #154)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #152))) :mode nil :granularity nil :parent #148) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #152) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #155) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #158)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #158) #("letsencrypt" 0 11 (:parent #162))) #("via the " 0 8 (:parent #158)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #158) #("certbot" 0 7 (:parent #164))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #158)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #158) #("certbox-service-type" 0 20 (:parent #166))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #158)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #158)) #("field in our " 0 13 (:parent #158)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #158)) #("configuration.\n" 0 15 (:parent #158))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #155)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #155) #("This service references " 0 24 (:parent #160)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #160)) #(", which we define below. It sends " 0 34 (:parent #160)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #160)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #160))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #155)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #155) #("Next we define a function we will use later in the " 0 51 (:parent #162)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #162) #("Configure Nginx Server Blocks" 0 29 (:parent #166))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #162))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #155)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #153)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #153))) :mode nil :granularity nil :parent #148) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #153) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #156) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #159))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #156)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #156) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #161))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #156) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #162) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #165) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #168)) #("\n" 0 1 (:parent #168))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #165) #(" " 0 2 (:parent #169)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #169)) #("provides a route " 0 17 (:parent #169)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #169)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #169)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #169)) #("command). Given away by the reference to " 0 41 (:parent #169)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #169) #("Nix" 0 3 (:parent #179))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #169)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #169) #("Nix Binary Cache" 0 16 (:parent #181))) #(".\n" 0 2 (:parent #169))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #165) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #170))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #165)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #165) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #172))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #165))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #162) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #166) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #169)) #("\n" 0 1 (:parent #169))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #166) #(" " 0 2 (:parent #170)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #170) #("NAR (Nix Archive Format)" 0 24 (:parent #174))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #170)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #170) #("hello" 0 5 (:parent #176))) #("package.\n" 0 9 (:parent #170))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #166) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #171))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #166)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #166)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #166) #(" The result is composed of a few parts:\n" 0 41 (:parent #174))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #166) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #178))) :mode item :granularity nil :parent #175) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #178) #("the guix store path\n" 0 20 (:parent #181)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #179))) :mode item :granularity nil :parent #175) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #179) #("a hash uniquely identifying the store item\n" 0 43 (:parent #182)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #180))) :mode item :granularity nil :parent #175) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #180) #("the package-name and version, separated by dashes\n" 0 50 (:parent #183))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #166) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #176)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #176)) #(".\n" 0 2 (:parent #176))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #166))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #162) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #167) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #170)) #("\n" 0 1 (:parent #170))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #167) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #171)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #171)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #171)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #171)) #("file.\n" 0 6 (:parent #171))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #167)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #167)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #167) #(" If the package is not available, this would return a " 0 55 (:parent #174)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #174)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #174)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #174)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #174)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #174)) #("below.\n" 0 7 (:parent #174))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #167) #(" #+begin" 0 9 (:parent #175)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #175) #("src" 0 3 (:parent #179))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #175)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #175) #("nar" 0 3 (:parent #181))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #175)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #175) #("pass" 0 4 (:parent #183))) #("\" url \";\")\n \"client" 0 25 (:parent #175)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #175) #("body" 0 4 (:parent #185))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #175) #("buffer" 0 6 (:parent #186))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #175) #("size" 0 4 (:parent #187))) #("256k;\"\n" 0 7 (:parent #175)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #96) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #99) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #102)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #102) #("Guix channels" 0 13 (:parent #106))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #102)))) #50 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #101))) :mode nil :granularity nil :parent #96) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #101) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #104) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #107)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #107)) #("field of our " 0 13 (:parent #107)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #107)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #107))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #104)))))) #26)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #26) #("In order to run Cuirass via the " 0 32 (:parent #29)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #29)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #29)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #29)) #("as a " 0 5 (:parent #29)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #29) #("G-Expression" 0 12 (:parent #37))) #("that will return a list of\n" 0 27 (:parent #29)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #29) #("cuirass specifications" 0 22 (:parent #39))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #29))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #26)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #26) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #31)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #31)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #31)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #31) #("Cuirass specification" 0 21 (:parent #37))) #("\ndocumentation for more details.\n" 0 33 (:parent #31))) #6)) . #0)))) "")
org-export-data((paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #44))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #90))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #136))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #182) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #185)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #185)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #185) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #198))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #185) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #199))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #185) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #200))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #185) #("Earlier this year " 0 18 (:parent #201)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #201) #("I announced on the guix mailing list" 0 36 (:parent #205))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #201)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #186))) :mode nil :granularity nil :parent #182) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #186) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #189) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #192))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #189) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #193) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #196) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #199) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #202) #("Improved Build Diversity" 0 24 (:parent #205)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #199)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #193) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #197) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #200) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #203) #("Reduced Latency" 0 15 (:parent #206)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #200)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #193) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #198) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #201) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #204) #("Increased Resilience" 0 20 (:parent #207)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #201)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #193) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #199) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #202) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #205) #("Community Contribution" 0 22 (:parent #208)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #202))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #189) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #194)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #194) #("here" 0 4 (:parent #198))) #(".\n" 0 2 (:parent #194))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #187))) :mode nil :granularity nil :parent #182) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #187) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #190) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #193))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #190) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #197) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #200) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #203) #("Processor" 0 9 (:parent #206)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #200)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #198) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #201) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #204) #("RAM" 0 3 (:parent #207)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #201)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #199) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #202) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #205) #("Storage" 0 7 (:parent #208)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #202)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #200) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #203) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #206) #("Network" 0 7 (:parent #209)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #203)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #201) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #204) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #207) #("Location" 0 8 (:parent #210)))) #(": Memphis TN\n" 0 13 (:parent #204))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #190) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #195))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #190) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #196))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #190) #("For more details, see the " 0 26 (:parent #197)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #197) #("Specifications section" 0 22 (:parent #201))) #("of the Cuirass Manual.\n" 0 23 (:parent #197))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #190) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #198))))) #136)) #90 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #140))) :mode nil :granularity nil :parent #136) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #140) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #143) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #146)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #146) #("guix publish" 0 12 (:parent #150))) #(", which Guix provides the " 0 26 (:parent #146)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #146) #("guix-publish-service-type" 0 25 (:parent #152))) #(",\nwhich is used in the " 0 23 (:parent #146)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #146)) #("field of " 0 9 (:parent #146)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #146)) #("definition.\n" 0 12 (:parent #146))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #143)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #143) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #148))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #141))) :mode nil :granularity nil :parent #136) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #141) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #144) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #147))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #144) #("To anonymize nginx access logs, the " 0 36 (:parent #148)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #148) #("anonip-service-type" 0 19 (:parent #152))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #148)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #148)) #("is defined.\n" 0 12 (:parent #148))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #144)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #144) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #150))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #144)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #144) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #152)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #152)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #152))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #144)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #144) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #154)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #154)) #("field of our\n" 0 13 (:parent #154)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #154)) #("declaration.\n" 0 13 (:parent #154))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #144)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #142))) :mode nil :granularity nil :parent #136) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #142) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #145) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #148)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #146))) :mode nil :granularity nil :parent #142) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #146) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #149) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #152)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #152) #("letsencrypt" 0 11 (:parent #156))) #("via the " 0 8 (:parent #152)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #152) #("certbot" 0 7 (:parent #158))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #152)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #152) #("certbox-service-type" 0 20 (:parent #160))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #152)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #152)) #("field in our " 0 13 (:parent #152)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #152)) #("configuration.\n" 0 15 (:parent #152))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #149)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #149) #("This service references " 0 24 (:parent #154)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #154)) #(", which we define below. It sends " 0 34 (:parent #154)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #154)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #154))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #149)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #149) #("Next we define a function we will use later in the " 0 51 (:parent #156)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #156) #("Configure Nginx Server Blocks" 0 29 (:parent #160))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #156))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #149)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #147)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #147))) :mode nil :granularity nil :parent #142) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #147) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #150) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #153))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #150)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #150) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #155))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #150) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #156) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #159) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #162)) #("\n" 0 1 (:parent #162))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #159) #(" " 0 2 (:parent #163)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #163)) #("provides a route " 0 17 (:parent #163)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #163)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #163)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #163)) #("command). Given away by the reference to " 0 41 (:parent #163)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #163) #("Nix" 0 3 (:parent #173))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #163)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #163) #("Nix Binary Cache" 0 16 (:parent #175))) #(".\n" 0 2 (:parent #163))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #159) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #164))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #159)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #159) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #166))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #159))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #156) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #160) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #163)) #("\n" 0 1 (:parent #163))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #160) #(" " 0 2 (:parent #164)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #164) #("NAR (Nix Archive Format)" 0 24 (:parent #168))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #164)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #164) #("hello" 0 5 (:parent #170))) #("package.\n" 0 9 (:parent #164))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #160) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #165))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #160)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #160)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #160) #(" The result is composed of a few parts:\n" 0 41 (:parent #168))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #160) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #172))) :mode item :granularity nil :parent #169) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #172) #("the guix store path\n" 0 20 (:parent #175)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #173))) :mode item :granularity nil :parent #169) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #173) #("a hash uniquely identifying the store item\n" 0 43 (:parent #176)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #174))) :mode item :granularity nil :parent #169) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #174) #("the package-name and version, separated by dashes\n" 0 50 (:parent #177))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #160) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #170)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #170)) #(".\n" 0 2 (:parent #170))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #160))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #156) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #161) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #164)) #("\n" 0 1 (:parent #164))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #161) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #165)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #165)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #165)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #165)) #("file.\n" 0 6 (:parent #165))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #161)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #161)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #161) #(" If the package is not available, this would return a " 0 55 (:parent #168)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #168)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #168)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #168)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #168)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #168)) #("below.\n" 0 7 (:parent #168))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #161) #(" #+begin" 0 9 (:parent #169)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #169) #("src" 0 3 (:parent #173))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #169)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #169) #("nar" 0 3 (:parent #175))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #169)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #169) #("pass" 0 4 (:parent #177))) #("\" url \";\")\n \"client" 0 25 (:parent #169)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #169) #("body" 0 4 (:parent #179))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #169) #("buffer" 0 6 (:parent #180))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #169) #("size" 0 4 (:parent #181))) #("256k;\"\n" 0 7 (:parent #169)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #90) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #93) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #96)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #96) #("Guix channels" 0 13 (:parent #100))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #96)))) #44 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #95))) :mode nil :granularity nil :parent #90) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #95) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #98) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #101)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #101)) #("field of our " 0 13 (:parent #101)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #101)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #101))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #98)))))) #20)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #20) #("In order to run Cuirass via the " 0 32 (:parent #23)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #23)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #23)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #23)) #("as a " 0 5 (:parent #23)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #23) #("G-Expression" 0 12 (:parent #31))) #("that will return a list of\n" 0 27 (:parent #23)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #23) #("cuirass specifications" 0 22 (:parent #33))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #23))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #20)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #20) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #25)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #25)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #25)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #25) #("Cuirass specification" 0 21 (:parent #31))) #("\ndocumentation for more details.\n" 0 33 (:parent #25))) #0)) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #0)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #0) #("Guix Configuration as a Channel" 0 31 (:parent #4))) #(".\n" 0 2 (:parent #0))) (:export-options (body-only) :back-end #s(org-export-backend :name html :parent nil :transcoders ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :options ((:html-doctype "HTML_DOCTYPE" nil org-html-doctype) (:html-container "HTML_CONTAINER" nil org-html-container-element) (:html-content-class "HTML_CONTENT_CLASS" nil org-html-content-class) (:description "DESCRIPTION" nil nil newline) (:keywords "KEYWORDS" nil nil space) (:html-html5-fancy nil "html5-fancy" org-html-html5-fancy) (:html-link-use-abs-url nil "html-link-use-abs-url" org-html-link-use-abs-url) (:html-link-home "HTML_LINK_HOME" nil org-html-link-home) (:html-link-up "HTML_LINK_UP" nil org-html-link-up) (:html-mathjax "HTML_MATHJAX" nil "" space) (:html-equation-reference-format "HTML_EQUATION_REFERENCE_FORMAT" nil org-html-equation-reference-format t) (:html-postamble nil "html-postamble" org-html-postamble) (:html-preamble nil "html-preamble" org-html-preamble) (:html-head "HTML_HEAD" nil org-html-head newline) (:html-head-extra "HTML_HEAD_EXTRA" nil org-html-head-extra newline) (:subtitle "SUBTITLE" nil nil parse) (:html-head-include-default-style nil "html-style" org-html-head-include-default-style) (:html-head-include-scripts nil "html-scripts" org-html-head-include-scripts) (:html-allow-name-attribute-in-anchors nil nil org-html-allow-name-attribute-in-anchors) (:html-divs nil nil org-html-divs) (:html-checkbox-type nil nil org-html-checkbox-type) (:html-extension nil nil org-html-extension) (:html-footnote-format nil nil org-html-footnote-format) (:html-footnote-separator nil nil org-html-footnote-separator) (:html-footnotes-section nil nil org-html-footnotes-section) (:html-format-drawer-function nil nil org-html-format-drawer-function) (:html-format-headline-function nil nil org-html-format-headline-function) (:html-format-inlinetask-function nil nil org-html-format-inlinetask-function) (:html-home/up-format nil nil org-html-home/up-format) (:html-indent nil nil org-html-indent) (:html-infojs-options nil nil org-html-infojs-options) (:html-infojs-template nil nil org-html-infojs-template) (:html-inline-image-rules nil nil org-html-inline-image-rules) (:html-link-org-files-as-html nil nil org-html-link-org-files-as-html) (:html-mathjax-options nil nil org-html-mathjax-options) (:html-mathjax-template nil nil org-html-mathjax-template) (:html-metadata-timestamp-format nil nil org-html-metadata-timestamp-format) (:html-postamble-format nil nil org-html-postamble-format) (:html-preamble-format nil nil org-html-preamble-format) (:html-prefer-user-labels nil nil org-html-prefer-user-labels) (:html-self-link-headlines nil nil org-html-self-link-headlines) (:html-table-align-individual-fields nil nil org-html-table-align-individual-fields) (:html-table-caption-above nil nil org-html-table-caption-above) (:html-table-data-tags nil nil org-html-table-data-tags) (:html-table-header-tags nil nil org-html-table-header-tags) (:html-table-use-header-tags-for-first-column nil nil org-html-table-use-header-tags-for-first-column) (:html-tag-class-prefix nil nil org-html-tag-class-prefix) (:html-text-markup-alist nil nil org-html-text-markup-alist) (:html-todo-kwd-class-prefix nil nil org-html-todo-kwd-class-prefix) (:html-toplevel-hlevel nil nil org-html-toplevel-hlevel) (:html-use-infojs nil nil org-html-use-infojs) (:html-validation-link nil nil org-html-validation-link) (:html-viewport nil nil org-html-viewport) (:html-inline-images nil nil org-html-inline-images) (:html-table-attributes nil nil org-html-table-default-attributes) (:html-table-row-open-tag nil nil org-html-table-row-open-tag) (:html-table-row-close-tag nil nil org-html-table-row-close-tag) (:html-xml-declaration nil nil org-html-xml-declaration) (:html-wrap-src-lines nil nil org-html-wrap-src-lines) (:html-klipsify-src nil nil org-html-klipsify-src) (:html-klipse-css nil nil org-html-klipse-css) (:html-klipse-js nil nil org-html-klipse-js) (:html-klipse-selection-script nil nil org-html-klipse-selection-script) (:infojs-opt "INFOJS_OPT" nil nil) (:creator "CREATOR" nil org-html-creator-string) (:with-latex nil "tex" org-html-with-latex) (:latex-header "LATEX_HEADER" nil nil newline)) :filters ((:filter-options . org-html-infojs-install-script) (:filter-parse-tree . org-html-image-link-filter) (:filter-final-output . org-html-final-function)) :blocks nil :menu (104 "Export to HTML" ((72 "As HTML buffer" org-html-export-as-html) (104 "As HTML file" org-html-export-to-html) (111 "As HTML file and open" (lambda (a s v b) (if a (org-html-export-to-html t s v b) (org-open-file (org-html-export-to-html nil s v b)))))))) :translate-alist ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data # :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil :html-divs ((preamble "div" "preamble") (content "div" "content") (postamble "div" "postamble")) :html-checkbox-type ascii :html-extension "html" :html-footnote-format "%s" :html-footnote-separator ", " :html-footnotes-section ") :html-format-headline-function org-html-format-headline-default-function :html-format-inlinetask-function org-html-format-inlinetask-default-function :html-home/up-format "" :html-indent nil :html-infojs-options ((path . "https://orgmode.org/org-info.js") (view . "info") (toc . :with-toc) (ftoc . "0") (tdepth . "max") (sdepth . "max") (mouse . "underline") (buttons . "0") (ltoc . "1") (up . :html-link-up) (home . :html-link-home)) :html-infojs-template "\n\n" :html-inline-image-rules (("file" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("http" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("https" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)")) :html-link-org-files-as-html t :html-mathjax-options ((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js") (scale 1.0) (align "center") (font "mathjax-modern") (overflow "overflow") (tags "ams") (indent "0em") (multlinewidth "85%") (tagindent ".8em") (tagside "right")) :html-mathjax-template "\n\n" :html-metadata-timestamp-format "%Y-%m-%d %a %H:%M" :html-postamble-format (("en" " \n" . " ") :html-table-header-tags ("" . " ") :html-table-use-header-tags-for-first-column nil :html-tag-class-prefix "" :html-text-markup-alist ((bold . "%s") (code . "%s") (underline . "%s") (verbatim . "" :html-table-row-close-tag " " :html-xml-declaration (("html" . "") ("php" . "\"; ?>")) :html-wrap-src-lines nil :html-klipsify-src nil :html-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css" :html-klipse-js "https://storage.googleapis.com/app.klipse.tech/plugin_prod/js/klipse_plugin.min.js" :html-klipse-selection-script "window.klipse_settings = {selector_eval_html: '.src-html',\n selector_eval_js: '.src-js',\n selector_eval_python_client: '.src-python',\n selector_eval_scheme: '.src-scheme',\n selector: '.src-clojure',\n selector_eval_ruby: '.src-ruby'};" :infojs-opt nil :creator "Emacs 29.4 (Org mode 9.6.15)" :with-latex t :latex-header "\\usepackage[margin=1.5cm]{geometry}\n\\usepackage{xcolor}\n\\definecolor{link}{HTML}{506060}\n\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :title (#("Setup of a Simple Guix Build Farm and Substitute Server" 0 55 (:parent #148))) :date nil :author (#("Collin J. Doering" 0 17 (:parent #152))) :email "unknown@genenetwork-development" :language "en" :select-tags ("export") :exclude-tags ("noexport") :headline-levels 3 :preserve-breaks nil :section-numbers nil :time-stamp-file t :with-archived-trees headline :with-author t :with-broken-links nil :with-clocks nil :with-creator nil :with-date t :with-drawers (not "LOGBOOK") :with-email nil :with-emphasize t :with-entities t :with-fixed-width t :with-footnotes t :with-inlinetasks t :with-planning nil :with-priority nil :with-properties nil :with-smart-quotes nil :with-special-strings t :with-statistics-cookies t :with-sub-superscript t :with-toc nil :with-tables t :with-tags t :with-tasks t :with-timestamps t :with-title t :with-todo-keywords t :cite-export (basic nil nil) :bibliography nil :filter-body nil :filter-bold nil :filter-babel-call nil :filter-center-block nil :filter-clock nil :filter-code nil :filter-diary-sexp nil :filter-drawer nil :filter-dynamic-block nil :filter-entity nil :filter-example-block nil :filter-export-block nil :filter-export-snippet nil :filter-final-output (org-html-final-function) :filter-fixed-width nil :filter-footnote-definition nil :filter-footnote-reference nil :filter-headline nil :filter-horizontal-rule nil :filter-inline-babel-call nil :filter-inline-src-block nil :filter-inlinetask nil :filter-italic nil :filter-item nil :filter-keyword nil :filter-latex-environment nil :filter-latex-fragment nil :filter-line-break nil :filter-link nil :filter-node-property nil :filter-options (org-html-infojs-install-script) :filter-paragraph nil :filter-parse-tree (org-html-image-link-filter) :filter-plain-list nil :filter-plain-text nil :filter-planning nil :filter-property-drawer nil :filter-quote-block nil :filter-radio-target nil :filter-section nil :filter-special-block nil :filter-src-block nil :filter-statistics-cookie nil :filter-strike-through nil :filter-subscript nil :filter-superscript nil :filter-table nil :filter-table-cell nil :filter-table-row nil :filter-target nil :filter-timestamp nil :filter-underline nil :filter-verbatim nil :filter-verse-block nil :ignore-list nil :parse-tree (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #338) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #341)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #341)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #341) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #354))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #341) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #355))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #341) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #356))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #341) #("Earlier this year " 0 18 (:parent #357)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #357) #("I announced on the guix mailing list" 0 36 (:parent #361))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #357)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #342))) :mode nil :granularity nil :parent #338) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #342) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #345) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #348))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #345) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #352) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #355) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #358) #("Improved Build Diversity" 0 24 (:parent #361)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #355)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #353) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #356) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #359) #("Reduced Latency" 0 15 (:parent #362)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #356)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #354) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #357) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #360) #("Increased Resilience" 0 20 (:parent #363)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #357)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #355) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #358) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #361) #("Community Contribution" 0 22 (:parent #364)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #358))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #345) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #350)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #350) #("here" 0 4 (:parent #354))) #(".\n" 0 2 (:parent #350))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #343))) :mode nil :granularity nil :parent #338) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #343) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #346) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #349))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #346) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #353) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #356) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #359) #("Processor" 0 9 (:parent #362)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #356)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #354) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #357) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #360) #("RAM" 0 3 (:parent #363)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #357)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #355) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #358) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #361) #("Storage" 0 7 (:parent #364)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #358)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #356) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #359) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #362) #("Network" 0 7 (:parent #365)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #359)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #357) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #360) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #363) #("Location" 0 8 (:parent #366)))) #(": Memphis TN\n" 0 13 (:parent #360))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #346) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #351))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #346) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #352))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #346) #("For more details, see the " 0 26 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #353) #("Specifications section" 0 22 (:parent #357))) #("of the Cuirass Manual.\n" 0 23 (:parent #353))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #346) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #354))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #344))) :mode nil :granularity nil :parent #338) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #347))) :mode section :granularity nil :parent #344) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #347) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #350) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #353) #("Guix channels" 0 13 (:parent #357))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #353)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #351))) :mode nil :granularity nil :parent #347) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #351) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #354) #("In order to run Cuirass via the " 0 32 (:parent #357)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #357)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #357)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #357)) #("as a " 0 5 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #357) #("G-Expression" 0 12 (:parent #365))) #("that will return a list of\n" 0 27 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #357) #("cuirass specifications" 0 22 (:parent #367))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #357))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #354)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #354) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #359)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #359)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #359)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #359) #("Cuirass specification" 0 21 (:parent #365))) #("\ndocumentation for more details.\n" 0 33 (:parent #359))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #354) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #360)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #360) #("Guix Configuration as a Channel" 0 31 (:parent #364))) #(".\n" 0 2 (:parent #360))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #352))) :mode nil :granularity nil :parent #347) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #352) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #355) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #358)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #358)) #("field of our " 0 13 (:parent #358)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #358)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #355))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #348))) :mode nil :granularity nil :parent #344) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #348) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #351) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #354)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #354) #("guix publish" 0 12 (:parent #358))) #(", which Guix provides the " 0 26 (:parent #354)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #354) #("guix-publish-service-type" 0 25 (:parent #360))) #(",\nwhich is used in the " 0 23 (:parent #354)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #354)) #("field of " 0 9 (:parent #354)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #354)) #("definition.\n" 0 12 (:parent #354))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #351)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #351) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #356))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #349))) :mode nil :granularity nil :parent #344) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #349) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #352) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #355))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #352) #("To anonymize nginx access logs, the " 0 36 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #356) #("anonip-service-type" 0 19 (:parent #360))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #356)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #356)) #("is defined.\n" 0 12 (:parent #356))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #352) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #352) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #360)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #360)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #352)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #352) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #362)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #362)) #("field of our\n" 0 13 (:parent #362)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #362)) #("declaration.\n" 0 13 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #352)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #350))) :mode nil :granularity nil :parent #344) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #350) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #353) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #356)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #354) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #357) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #360)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #360) #("letsencrypt" 0 11 (:parent #364))) #("via the " 0 8 (:parent #360)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #360) #("certbot" 0 7 (:parent #366))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #360) #("certbox-service-type" 0 20 (:parent #368))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #360)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #360)) #("field in our " 0 13 (:parent #360)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #360)) #("configuration.\n" 0 15 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #357) #("This service references " 0 24 (:parent #362)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #362)) #(", which we define below. It sends " 0 34 (:parent #362)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #362)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #357) #("Next we define a function we will use later in the " 0 51 (:parent #364)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #364) #("Configure Nginx Server Blocks" 0 29 (:parent #368))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #364))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #357)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #355)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #355) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #358) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #358)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #358) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #363))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #358) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #367) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #370)) #("\n" 0 1 (:parent #370))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #367) #(" " 0 2 (:parent #371)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #371)) #("provides a route " 0 17 (:parent #371)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #371)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #371)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #371)) #("command). Given away by the reference to " 0 41 (:parent #371)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #371) #("Nix" 0 3 (:parent #381))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #371)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #371) #("Nix Binary Cache" 0 16 (:parent #383))) #(".\n" 0 2 (:parent #371))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #367) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #372))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #367)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #367) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #374))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #367))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #368) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #371)) #("\n" 0 1 (:parent #371))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #368) #(" " 0 2 (:parent #372)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #372) #("NAR (Nix Archive Format)" 0 24 (:parent #376))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #372)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #372) #("hello" 0 5 (:parent #378))) #("package.\n" 0 9 (:parent #372))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #368) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #368)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #368)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #368) #(" The result is composed of a few parts:\n" 0 41 (:parent #376))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #368) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #380))) :mode item :granularity nil :parent #377) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #380) #("the guix store path\n" 0 20 (:parent #383)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #381))) :mode item :granularity nil :parent #377) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #381) #("a hash uniquely identifying the store item\n" 0 43 (:parent #384)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #382))) :mode item :granularity nil :parent #377) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #382) #("the package-name and version, separated by dashes\n" 0 50 (:parent #385))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #368) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #378)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #378)) #(".\n" 0 2 (:parent #378))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #368))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #369) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #372)) #("\n" 0 1 (:parent #372))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #369) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #373)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #373)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #373)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #373)) #("file.\n" 0 6 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #369)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #369)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #369) #(" If the package is not available, this would return a " 0 55 (:parent #376)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #376)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #376)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #376)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #376)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #376)) #("below.\n" 0 7 (:parent #376))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #369) #(" #+begin" 0 9 (:parent #377)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #377) #("src" 0 3 (:parent #381))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #377)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #377) #("nar" 0 3 (:parent #383))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #377)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #377) #("pass" 0 4 (:parent #385))) #("\" url \";\")\n \"client" 0 25 (:parent #377)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #377) #("body" 0 4 (:parent #387))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #377) #("buffer" 0 6 (:parent #388))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #377) #("size" 0 4 (:parent #389))) #("256k;\"\n" 0 7 (:parent #377)))))))))) :headline-offset 0 :headline-numbering nil :id-alist nil :citations nil :internal-references (("org1d65611" headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #350))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #396))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #442) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #445)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #445)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #445) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #458))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #445) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #459))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #445) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #460))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #445) #("Earlier this year " 0 18 (:parent #461)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #461) #("I announced on the guix mailing list" 0 36 (:parent #465))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #461)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #446))) :mode nil :granularity nil :parent #442) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #446) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #449) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #452))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #449) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #456) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #459) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #462) #("Improved Build Diversity" 0 24 (:parent #465)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #459)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #457) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #460) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #463) #("Reduced Latency" 0 15 (:parent #466)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #460)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #458) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #461) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #464) #("Increased Resilience" 0 20 (:parent #467)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #461)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #459) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #462) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #465) #("Community Contribution" 0 22 (:parent #468)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #462))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #449) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #454)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #454) #("here" 0 4 (:parent #458))) #(".\n" 0 2 (:parent #454))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #447))) :mode nil :granularity nil :parent #442) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #447) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #450) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #453))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #450) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #457) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #460) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #463) #("Processor" 0 9 (:parent #466)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #460)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #458) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #461) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #464) #("RAM" 0 3 (:parent #467)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #461)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #459) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #462) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #465) #("Storage" 0 7 (:parent #468)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #462)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #460) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #463) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #466) #("Network" 0 7 (:parent #469)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #463)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #461) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #464) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #467) #("Location" 0 8 (:parent #470)))) #(": Memphis TN\n" 0 13 (:parent #464))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #450) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #455))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #450) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #456))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #450) #("For more details, see the " 0 26 (:parent #457)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #457) #("Specifications section" 0 22 (:parent #461))) #("of the Cuirass Manual.\n" 0 23 (:parent #457))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #450) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #458))))) #396)) #350 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #400))) :mode nil :granularity nil :parent #396) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #400) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #403) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #406)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #406) #("guix publish" 0 12 (:parent #410))) #(", which Guix provides the " 0 26 (:parent #406)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #406) #("guix-publish-service-type" 0 25 (:parent #412))) #(",\nwhich is used in the " 0 23 (:parent #406)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #406)) #("field of " 0 9 (:parent #406)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #406)) #("definition.\n" 0 12 (:parent #406))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #403)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #403) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #408))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #401))) :mode nil :granularity nil :parent #396) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #401) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #404) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #407))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #404) #("To anonymize nginx access logs, the " 0 36 (:parent #408)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #408) #("anonip-service-type" 0 19 (:parent #412))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #408)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #408)) #("is defined.\n" 0 12 (:parent #408))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #404) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #410))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #404) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #412)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #412)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #404)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #404) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #414)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #414)) #("field of our\n" 0 13 (:parent #414)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #414)) #("declaration.\n" 0 13 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #404)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #402))) :mode nil :granularity nil :parent #396) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #402) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #405) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #408)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #406))) :mode nil :granularity nil :parent #402) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #406) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #409) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #412)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #412) #("letsencrypt" 0 11 (:parent #416))) #("via the " 0 8 (:parent #412)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #412) #("certbot" 0 7 (:parent #418))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #412)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #412) #("certbox-service-type" 0 20 (:parent #420))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #412)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #412)) #("field in our " 0 13 (:parent #412)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #412)) #("configuration.\n" 0 15 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #409) #("This service references " 0 24 (:parent #414)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #414)) #(", which we define below. It sends " 0 34 (:parent #414)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #414)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #409) #("Next we define a function we will use later in the " 0 51 (:parent #416)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #416) #("Configure Nginx Server Blocks" 0 29 (:parent #420))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #416))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #409)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #407)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #407) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #410) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #413))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #410)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #410) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #415))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #419) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #422)) #("\n" 0 1 (:parent #422))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #419) #(" " 0 2 (:parent #423)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #423)) #("provides a route " 0 17 (:parent #423)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #423)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #423)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #423)) #("command). Given away by the reference to " 0 41 (:parent #423)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #423) #("Nix" 0 3 (:parent #433))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #423)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #423) #("Nix Binary Cache" 0 16 (:parent #435))) #(".\n" 0 2 (:parent #423))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #419) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #424))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #419)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #419) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #419))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #420) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #423)) #("\n" 0 1 (:parent #423))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #420) #(" " 0 2 (:parent #424)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #424) #("NAR (Nix Archive Format)" 0 24 (:parent #428))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #424)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #424) #("hello" 0 5 (:parent #430))) #("package.\n" 0 9 (:parent #424))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #420) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #420)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #420)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #420) #(" The result is composed of a few parts:\n" 0 41 (:parent #428))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #420) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #432))) :mode item :granularity nil :parent #429) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #432) #("the guix store path\n" 0 20 (:parent #435)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #433))) :mode item :granularity nil :parent #429) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #433) #("a hash uniquely identifying the store item\n" 0 43 (:parent #436)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #434))) :mode item :granularity nil :parent #429) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #434) #("the package-name and version, separated by dashes\n" 0 50 (:parent #437))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #420) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #430)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #430)) #(".\n" 0 2 (:parent #430))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #420))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #421) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #424)) #("\n" 0 1 (:parent #424))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #421) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #425)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #425)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #425)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #425)) #("file.\n" 0 6 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #421)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #421)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #421) #(" If the package is not available, this would return a " 0 55 (:parent #428)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #428)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #428)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #428)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #428)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #428)) #("below.\n" 0 7 (:parent #428))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #421) #(" #+begin" 0 9 (:parent #429)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #429) #("src" 0 3 (:parent #433))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #429)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #429) #("nar" 0 3 (:parent #435))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #429)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #429) #("pass" 0 4 (:parent #437))) #("\" url \";\")\n \"client" 0 25 (:parent #429)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #429) #("body" 0 4 (:parent #439))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #429) #("buffer" 0 6 (:parent #440))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #429) #("size" 0 4 (:parent #441))) #("256k;\"\n" 0 7 (:parent #429)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #350) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #353) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #356) #("Guix channels" 0 13 (:parent #360))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #356)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #354) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #357) #("In order to run Cuirass via the " 0 32 (:parent #360)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #360)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #360)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #360)) #("as a " 0 5 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #360) #("G-Expression" 0 12 (:parent #368))) #("that will return a list of\n" 0 27 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #360) #("cuirass specifications" 0 22 (:parent #370))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #357)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #357) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #362)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #362)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #362)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #362) #("Cuirass specification" 0 21 (:parent #368))) #("\ndocumentation for more details.\n" 0 33 (:parent #362))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #357) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #363)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #363) #("Guix Configuration as a Channel" 0 31 (:parent #367))) #(".\n" 0 2 (:parent #363))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #355) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #358) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #361)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #361)) #("field of our " 0 13 (:parent #361)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #361)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #358))))) ((other "Cuirass" "-" "Building" "Packages") . 30823953) ((headline "Cuirass" "-" "Building" "Packages") . 30823953) ("org46b8c57" headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #353))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #399) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #402)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #402)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #402) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #415))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #402) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #416))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #402) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #417))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #402) #("Earlier this year " 0 18 (:parent #418)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #418) #("I announced on the guix mailing list" 0 36 (:parent #422))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #418)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #403))) :mode nil :granularity nil :parent #399) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #403) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #406) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #409))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #406) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #413) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #416) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #419) #("Improved Build Diversity" 0 24 (:parent #422)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #416)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #414) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #417) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #420) #("Reduced Latency" 0 15 (:parent #423)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #417)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #415) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #418) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #421) #("Increased Resilience" 0 20 (:parent #424)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #418)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #416) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #419) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #422) #("Community Contribution" 0 22 (:parent #425)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #419))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #406) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #411)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #411) #("here" 0 4 (:parent #415))) #(".\n" 0 2 (:parent #411))))) #353 (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #405))) :mode nil :granularity nil :parent #399) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #408))) :mode section :granularity nil :parent #405) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #408) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #411) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #414)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #414) #("Guix channels" 0 13 (:parent #418))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #414)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #412) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #415) #("In order to run Cuirass via the " 0 32 (:parent #418)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #418)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #418)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #418)) #("as a " 0 5 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #418) #("G-Expression" 0 12 (:parent #426))) #("that will return a list of\n" 0 27 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #418) #("cuirass specifications" 0 22 (:parent #428))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #415)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #415) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #420)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #420)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #420) #("Cuirass specification" 0 21 (:parent #426))) #("\ndocumentation for more details.\n" 0 33 (:parent #420))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #415) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #421)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #421) #("Guix Configuration as a Channel" 0 31 (:parent #425))) #(".\n" 0 2 (:parent #421))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #413) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #416) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #419)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #419)) #("field of our " 0 13 (:parent #419)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #419)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #416))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #409))) :mode nil :granularity nil :parent #405) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #409) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #412) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #415)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #415) #("guix publish" 0 12 (:parent #419))) #(", which Guix provides the " 0 26 (:parent #415)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #415) #("guix-publish-service-type" 0 25 (:parent #421))) #(",\nwhich is used in the " 0 23 (:parent #415)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #415)) #("field of " 0 9 (:parent #415)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #415)) #("definition.\n" 0 12 (:parent #415))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #412)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #412) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #417))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #410))) :mode nil :granularity nil :parent #405) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #410) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #413) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #416))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #413) #("To anonymize nginx access logs, the " 0 36 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #417) #("anonip-service-type" 0 19 (:parent #421))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #417)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #417)) #("is defined.\n" 0 12 (:parent #417))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #413) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #413) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #421)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #421)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #413)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #413) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #423)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #423)) #("field of our\n" 0 13 (:parent #423)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #423)) #("declaration.\n" 0 13 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #413)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #411))) :mode nil :granularity nil :parent #405) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #411) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #414) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #417)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #415) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #418) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #421)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #421) #("letsencrypt" 0 11 (:parent #425))) #("via the " 0 8 (:parent #421)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #421) #("certbot" 0 7 (:parent #427))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #421) #("certbox-service-type" 0 20 (:parent #429))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #421)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #421)) #("field in our " 0 13 (:parent #421)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #421)) #("configuration.\n" 0 15 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #418) #("This service references " 0 24 (:parent #423)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #423)) #(", which we define below. It sends " 0 34 (:parent #423)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #423)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #418) #("Next we define a function we will use later in the " 0 51 (:parent #425)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #425) #("Configure Nginx Server Blocks" 0 29 (:parent #429))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #418)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #416)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #416) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #419) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #419)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #419) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #424))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #419) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #428) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #431)) #("\n" 0 1 (:parent #431))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #428) #(" " 0 2 (:parent #432)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #432)) #("provides a route " 0 17 (:parent #432)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #432)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #432)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #432)) #("command). Given away by the reference to " 0 41 (:parent #432)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #432) #("Nix" 0 3 (:parent #442))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #432)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #432) #("Nix Binary Cache" 0 16 (:parent #444))) #(".\n" 0 2 (:parent #432))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #428) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #433))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #428)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #428) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #435))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #428))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #429) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #432)) #("\n" 0 1 (:parent #432))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #429) #(" " 0 2 (:parent #433)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #433) #("NAR (Nix Archive Format)" 0 24 (:parent #437))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #433)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #433) #("hello" 0 5 (:parent #439))) #("package.\n" 0 9 (:parent #433))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #429) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #429)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #429)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #429) #(" The result is composed of a few parts:\n" 0 41 (:parent #437))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #429) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #441))) :mode item :granularity nil :parent #438) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #441) #("the guix store path\n" 0 20 (:parent #444)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #442))) :mode item :granularity nil :parent #438) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #442) #("a hash uniquely identifying the store item\n" 0 43 (:parent #445)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #443))) :mode item :granularity nil :parent #438) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #443) #("the package-name and version, separated by dashes\n" 0 50 (:parent #446))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #429) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #439)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #439)) #(".\n" 0 2 (:parent #439))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #429))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #430) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #433)) #("\n" 0 1 (:parent #433))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #430) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #434)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #434)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #434)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #434)) #("file.\n" 0 6 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #430)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #430)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #430) #(" If the package is not available, this would return a " 0 55 (:parent #437)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #437)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #437)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #437)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #437)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #437)) #("below.\n" 0 7 (:parent #437))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #430) #(" #+begin" 0 9 (:parent #438)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #438) #("src" 0 3 (:parent #442))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #438)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #438) #("nar" 0 3 (:parent #444))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #438)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #438) #("pass" 0 4 (:parent #446))) #("\" url \";\")\n \"client" 0 25 (:parent #438)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #438) #("body" 0 4 (:parent #448))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #438) #("buffer" 0 6 (:parent #449))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #438) #("size" 0 4 (:parent #450))) #("256k;\"\n" 0 7 (:parent #438))))))))))) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #353) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #356) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #359))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #356) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #363) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #366) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #369) #("Processor" 0 9 (:parent #372)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #366)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #364) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #367) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #370) #("RAM" 0 3 (:parent #373)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #367)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #365) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #368) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #371) #("Storage" 0 7 (:parent #374)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #368)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #366) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #369) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #372) #("Network" 0 7 (:parent #375)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #369)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #367) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #370) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #373) #("Location" 0 8 (:parent #376)))) #(": Memphis TN\n" 0 13 (:parent #370))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #356) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #361))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #356) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #362))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #356) #("For more details, see the " 0 26 (:parent #363)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #363) #("Specifications section" 0 22 (:parent #367))) #("of the Cuirass Manual.\n" 0 23 (:parent #363))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #356) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #364))))) ((other "Hardware" "and" "Infrastructure") . 74157143) ((headline "Hardware" "and" "Infrastructure") . 74157143) ("orgcc40a3d" headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #356))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #402) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #405)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #405)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #405) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #418))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #405) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #419))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #405) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #420))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #405) #("Earlier this year " 0 18 (:parent #421)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #421) #("I announced on the guix mailing list" 0 36 (:parent #425))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #421)))) #356 (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #407) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #410) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #413))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #417) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #420) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #423) #("Processor" 0 9 (:parent #426)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #420)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #418) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #421) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #424) #("RAM" 0 3 (:parent #427)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #421)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #419) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #422) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #425) #("Storage" 0 7 (:parent #428)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #422)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #420) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #423) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #426) #("Network" 0 7 (:parent #429)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #423)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #421) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #424) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #427) #("Location" 0 8 (:parent #430)))) #(": Memphis TN\n" 0 13 (:parent #424))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #410) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #415))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #410) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #416))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #410) #("For more details, see the " 0 26 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #417) #("Specifications section" 0 22 (:parent #421))) #("of the Cuirass Manual.\n" 0 23 (:parent #417))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #410) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #418))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #408))) :mode nil :granularity nil :parent #402) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #411))) :mode section :granularity nil :parent #408) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #411) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #414) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #417) #("Guix channels" 0 13 (:parent #421))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #417)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #415) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #418) #("In order to run Cuirass via the " 0 32 (:parent #421)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #421)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #421)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #421)) #("as a " 0 5 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #421) #("G-Expression" 0 12 (:parent #429))) #("that will return a list of\n" 0 27 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #421) #("cuirass specifications" 0 22 (:parent #431))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #418)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #418) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #423)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #423)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #423)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #423) #("Cuirass specification" 0 21 (:parent #429))) #("\ndocumentation for more details.\n" 0 33 (:parent #423))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #418) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #424)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #424) #("Guix Configuration as a Channel" 0 31 (:parent #428))) #(".\n" 0 2 (:parent #424))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #416) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #419) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #422)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #422)) #("field of our " 0 13 (:parent #422)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #422)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #419))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #412) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #415) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #418) #("guix publish" 0 12 (:parent #422))) #(", which Guix provides the " 0 26 (:parent #418)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #418) #("guix-publish-service-type" 0 25 (:parent #424))) #(",\nwhich is used in the " 0 23 (:parent #418)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #418)) #("field of " 0 9 (:parent #418)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #418)) #("definition.\n" 0 12 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #415)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #415) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #420))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #413) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #416) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #419))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #416) #("To anonymize nginx access logs, the " 0 36 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #420) #("anonip-service-type" 0 19 (:parent #424))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #420)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #420)) #("is defined.\n" 0 12 (:parent #420))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #416) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #416) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #424)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #424)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #416)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #416) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #426)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #426)) #("field of our\n" 0 13 (:parent #426)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #426)) #("declaration.\n" 0 13 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #416)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #414))) :mode nil :granularity nil :parent #408) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #414) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #417) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #420)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #418))) :mode nil :granularity nil :parent #414) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #418) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #421) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #424)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #424) #("letsencrypt" 0 11 (:parent #428))) #("via the " 0 8 (:parent #424)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #424) #("certbot" 0 7 (:parent #430))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #424)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #424) #("certbox-service-type" 0 20 (:parent #432))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #424)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #424)) #("field in our " 0 13 (:parent #424)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #424)) #("configuration.\n" 0 15 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #421) #("This service references " 0 24 (:parent #426)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #426)) #(", which we define below. It sends " 0 34 (:parent #426)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #426)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #421) #("Next we define a function we will use later in the " 0 51 (:parent #428)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #428) #("Configure Nginx Server Blocks" 0 29 (:parent #432))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #428))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #421)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #419)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #419))) :mode nil :granularity nil :parent #414) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #419) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #422) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #422)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #422) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #427))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #422) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #431) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #434)) #("\n" 0 1 (:parent #434))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #431) #(" " 0 2 (:parent #435)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #435)) #("provides a route " 0 17 (:parent #435)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #435)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #435)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #435)) #("command). Given away by the reference to " 0 41 (:parent #435)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #435) #("Nix" 0 3 (:parent #445))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #435)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #435) #("Nix Binary Cache" 0 16 (:parent #447))) #(".\n" 0 2 (:parent #435))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #431) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #436))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #431)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #431) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #438))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #431))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #432) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #435)) #("\n" 0 1 (:parent #435))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #432) #(" " 0 2 (:parent #436)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #436) #("NAR (Nix Archive Format)" 0 24 (:parent #440))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #436)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #436) #("hello" 0 5 (:parent #442))) #("package.\n" 0 9 (:parent #436))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #432) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #432)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #432)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #432) #(" The result is composed of a few parts:\n" 0 41 (:parent #440))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #432) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #444))) :mode item :granularity nil :parent #441) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #444) #("the guix store path\n" 0 20 (:parent #447)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #445))) :mode item :granularity nil :parent #441) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #445) #("a hash uniquely identifying the store item\n" 0 43 (:parent #448)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #446))) :mode item :granularity nil :parent #441) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #446) #("the package-name and version, separated by dashes\n" 0 50 (:parent #449))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #432) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #442)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #442)) #(".\n" 0 2 (:parent #442))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #432))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #433) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #436)) #("\n" 0 1 (:parent #436))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #433) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #437)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #437)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #437)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #437)) #("file.\n" 0 6 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #433)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #433)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #433) #(" If the package is not available, this would return a " 0 55 (:parent #440)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #440)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #440)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #440)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #440)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #440)) #("below.\n" 0 7 (:parent #440))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #433) #(" #+begin" 0 9 (:parent #441)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #441) #("src" 0 3 (:parent #445))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #441)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #441) #("nar" 0 3 (:parent #447))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #441)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #441) #("pass" 0 4 (:parent #449))) #("\" url \";\")\n \"client" 0 25 (:parent #441)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #441) #("body" 0 4 (:parent #451))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #441) #("buffer" 0 6 (:parent #452))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #441) #("size" 0 4 (:parent #453))) #("256k;\"\n" 0 7 (:parent #441))))))))))) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #356) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #359) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #362))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #359) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #366) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #369) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #372) #("Improved Build Diversity" 0 24 (:parent #375)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #369)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #367) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #370) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #373) #("Reduced Latency" 0 15 (:parent #376)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #370)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #368) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #371) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #374) #("Increased Resilience" 0 20 (:parent #377)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #371)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #369) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #372) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #375) #("Community Contribution" 0 22 (:parent #378)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #372))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #359) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #364)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #364) #("here" 0 4 (:parent #368))) #(".\n" 0 2 (:parent #364))))) ((other "Why" "Build" "Another" "Substitute" "Server?") . 214174269) ((headline "Why" "Build" "Another" "Substitute" "Server?") . 214174269)) :resolve-fuzzy-link-cache #))
#f(compiled-function (element) #)((paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #44))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #90))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #136))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #182) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #185)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #185)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #185)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #185) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #198))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #185) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #199))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #185) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #200))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #185) #("Earlier this year " 0 18 (:parent #201)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #201) #("I announced on the guix mailing list" 0 36 (:parent #205))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #201)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #186))) :mode nil :granularity nil :parent #182) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #186) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #189) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #192))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #189) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #193) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #196) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #199) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #202) #("Improved Build Diversity" 0 24 (:parent #205)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #199)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #193) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #197) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #200) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #203) #("Reduced Latency" 0 15 (:parent #206)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #200)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #193) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #198) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #201) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #204) #("Increased Resilience" 0 20 (:parent #207)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #201)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #193) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #199) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #202) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #205) #("Community Contribution" 0 22 (:parent #208)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #202))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #189) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #194)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #194) #("here" 0 4 (:parent #198))) #(".\n" 0 2 (:parent #194))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #187))) :mode nil :granularity nil :parent #182) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #187) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #190) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #193))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #190) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #197) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #200) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #203) #("Processor" 0 9 (:parent #206)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #200)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #198) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #201) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #204) #("RAM" 0 3 (:parent #207)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #201)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #199) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #202) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #205) #("Storage" 0 7 (:parent #208)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #202)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #200) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #203) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #206) #("Network" 0 7 (:parent #209)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #203)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #201) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #204) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #207) #("Location" 0 8 (:parent #210)))) #(": Memphis TN\n" 0 13 (:parent #204))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #190) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #195))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #190) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #196))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #190) #("For more details, see the " 0 26 (:parent #197)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #197) #("Specifications section" 0 22 (:parent #201))) #("of the Cuirass Manual.\n" 0 23 (:parent #197))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #190) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #198))))) #136)) #90 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #140))) :mode nil :granularity nil :parent #136) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #140) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #143) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #146)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #146) #("guix publish" 0 12 (:parent #150))) #(", which Guix provides the " 0 26 (:parent #146)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #146) #("guix-publish-service-type" 0 25 (:parent #152))) #(",\nwhich is used in the " 0 23 (:parent #146)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #146)) #("field of " 0 9 (:parent #146)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #146)) #("definition.\n" 0 12 (:parent #146))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #143)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #143) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #148))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #141))) :mode nil :granularity nil :parent #136) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #141) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #144) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #147))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #144) #("To anonymize nginx access logs, the " 0 36 (:parent #148)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #148) #("anonip-service-type" 0 19 (:parent #152))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #148)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #148)) #("is defined.\n" 0 12 (:parent #148))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #144)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #144) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #150))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #144)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #144) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #152)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #152)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #152))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #144)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #144) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #154)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #154)) #("field of our\n" 0 13 (:parent #154)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #154)) #("declaration.\n" 0 13 (:parent #154))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #144)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #142))) :mode nil :granularity nil :parent #136) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #142) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #145) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #148)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #146))) :mode nil :granularity nil :parent #142) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #146) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #149) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #152)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #152) #("letsencrypt" 0 11 (:parent #156))) #("via the " 0 8 (:parent #152)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #152) #("certbot" 0 7 (:parent #158))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #152)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #152) #("certbox-service-type" 0 20 (:parent #160))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #152)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #152)) #("field in our " 0 13 (:parent #152)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #152)) #("configuration.\n" 0 15 (:parent #152))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #149)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #149) #("This service references " 0 24 (:parent #154)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #154)) #(", which we define below. It sends " 0 34 (:parent #154)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #154)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #154))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #149)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #149) #("Next we define a function we will use later in the " 0 51 (:parent #156)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #156) #("Configure Nginx Server Blocks" 0 29 (:parent #160))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #156))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #149)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #147)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #147))) :mode nil :granularity nil :parent #142) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #147) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #150) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #153))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #150)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #150) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #155))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #150) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #156) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #159) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #162)) #("\n" 0 1 (:parent #162))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #159) #(" " 0 2 (:parent #163)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #163)) #("provides a route " 0 17 (:parent #163)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #163)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #163)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #163)) #("command). Given away by the reference to " 0 41 (:parent #163)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #163) #("Nix" 0 3 (:parent #173))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #163)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #163) #("Nix Binary Cache" 0 16 (:parent #175))) #(".\n" 0 2 (:parent #163))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #159) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #164))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #159)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #159) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #166))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #159))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #156) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #160) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #163)) #("\n" 0 1 (:parent #163))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #160) #(" " 0 2 (:parent #164)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #164) #("NAR (Nix Archive Format)" 0 24 (:parent #168))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #164)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #164) #("hello" 0 5 (:parent #170))) #("package.\n" 0 9 (:parent #164))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #160) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #165))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #160)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #160)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #160) #(" The result is composed of a few parts:\n" 0 41 (:parent #168))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #160) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #172))) :mode item :granularity nil :parent #169) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #172) #("the guix store path\n" 0 20 (:parent #175)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #173))) :mode item :granularity nil :parent #169) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #173) #("a hash uniquely identifying the store item\n" 0 43 (:parent #176)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #174))) :mode item :granularity nil :parent #169) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #174) #("the package-name and version, separated by dashes\n" 0 50 (:parent #177))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #160) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #170)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #170)) #(".\n" 0 2 (:parent #170))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #160))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #156) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #161) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #164)) #("\n" 0 1 (:parent #164))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #161) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #165)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #165)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #165)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #165)) #("file.\n" 0 6 (:parent #165))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #161)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #161)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #161) #(" If the package is not available, this would return a " 0 55 (:parent #168)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #168)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #168)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #168)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #168)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #168)) #("below.\n" 0 7 (:parent #168))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #161) #(" #+begin" 0 9 (:parent #169)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #169) #("src" 0 3 (:parent #173))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #169)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #169) #("nar" 0 3 (:parent #175))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #169)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #169) #("pass" 0 4 (:parent #177))) #("\" url \";\")\n \"client" 0 25 (:parent #169)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #169) #("body" 0 4 (:parent #179))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #169) #("buffer" 0 6 (:parent #180))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #169) #("size" 0 4 (:parent #181))) #("256k;\"\n" 0 7 (:parent #169)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #90) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #93) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #96)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #96) #("Guix channels" 0 13 (:parent #100))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #96)))) #44 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #95))) :mode nil :granularity nil :parent #90) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #95) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #98) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #101)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #101)) #("field of our " 0 13 (:parent #101)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #101)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #101))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #98)))))) #20)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #20) #("In order to run Cuirass via the " 0 32 (:parent #23)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #23)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #23)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #23)) #("as a " 0 5 (:parent #23)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #23) #("G-Expression" 0 12 (:parent #31))) #("that will return a list of\n" 0 27 (:parent #23)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #23) #("cuirass specifications" 0 22 (:parent #33))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #23))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #20)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #20) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #25)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #25)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #25)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #25) #("Cuirass specification" 0 21 (:parent #31))) #("\ndocumentation for more details.\n" 0 33 (:parent #25))) #0)) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #0)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #0) #("Guix Configuration as a Channel" 0 31 (:parent #4))) #(".\n" 0 2 (:parent #0))))
mapconcat(#f(compiled-function (element) #) ((paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #45))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #91))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #137))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #183) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #186)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #186)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #186)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #186)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #186)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #186)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #186)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #186)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #186)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #186)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #186) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #199))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #186) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #200))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #186) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #201))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #186) #("Earlier this year " 0 18 (:parent #202)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #202) #("I announced on the guix mailing list" 0 36 (:parent #206))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #202)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #187))) :mode nil :granularity nil :parent #183) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #187) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #190) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #193))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #190) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #197) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #200) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #203) #("Improved Build Diversity" 0 24 (:parent #206)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #200)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #198) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #201) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #204) #("Reduced Latency" 0 15 (:parent #207)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #201)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #199) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #202) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #205) #("Increased Resilience" 0 20 (:parent #208)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #202)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #194) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #200) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #203) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #206) #("Community Contribution" 0 22 (:parent #209)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #203))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #190) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #195)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #195) #("here" 0 4 (:parent #199))) #(".\n" 0 2 (:parent #195))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #188))) :mode nil :granularity nil :parent #183) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #188) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #191) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #194))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #191) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #195) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #198) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #201) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #204) #("Processor" 0 9 (:parent #207)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #201)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #195) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #199) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #202) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #205) #("RAM" 0 3 (:parent #208)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #202)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #195) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #200) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #203) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #206) #("Storage" 0 7 (:parent #209)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #203)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #195) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #201) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #204) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #207) #("Network" 0 7 (:parent #210)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #204)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #195) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #202) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #205) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #208) #("Location" 0 8 (:parent #211)))) #(": Memphis TN\n" 0 13 (:parent #205))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #191) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #196))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #191) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #197))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #191) #("For more details, see the " 0 26 (:parent #198)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #198) #("Specifications section" 0 22 (:parent #202))) #("of the Cuirass Manual.\n" 0 23 (:parent #198))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #191) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #199))))) #137)) #91 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #141))) :mode nil :granularity nil :parent #137) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #141) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #144) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #147)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #147) #("guix publish" 0 12 (:parent #151))) #(", which Guix provides the " 0 26 (:parent #147)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #147) #("guix-publish-service-type" 0 25 (:parent #153))) #(",\nwhich is used in the " 0 23 (:parent #147)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #147)) #("field of " 0 9 (:parent #147)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #147)) #("definition.\n" 0 12 (:parent #147))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #144)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #144) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #149))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #142))) :mode nil :granularity nil :parent #137) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #142) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #145) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #148))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #145) #("To anonymize nginx access logs, the " 0 36 (:parent #149)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #149) #("anonip-service-type" 0 19 (:parent #153))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #149)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #149)) #("is defined.\n" 0 12 (:parent #149))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #145)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #145) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #151))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #145)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #145) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #153)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #153)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #153))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #145)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #145) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #155)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #155)) #("field of our\n" 0 13 (:parent #155)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #155)) #("declaration.\n" 0 13 (:parent #155))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #145)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #143))) :mode nil :granularity nil :parent #137) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #143) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #146) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #149)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #147))) :mode nil :granularity nil :parent #143) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #147) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #150) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #153)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #153) #("letsencrypt" 0 11 (:parent #157))) #("via the " 0 8 (:parent #153)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #153) #("certbot" 0 7 (:parent #159))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #153)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #153) #("certbox-service-type" 0 20 (:parent #161))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #153)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #153)) #("field in our " 0 13 (:parent #153)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #153)) #("configuration.\n" 0 15 (:parent #153))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #150)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #150) #("This service references " 0 24 (:parent #155)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #155)) #(", which we define below. It sends " 0 34 (:parent #155)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #155)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #155))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #150)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #150) #("Next we define a function we will use later in the " 0 51 (:parent #157)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #157) #("Configure Nginx Server Blocks" 0 29 (:parent #161))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #157))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #150)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #148)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #148))) :mode nil :granularity nil :parent #143) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #148) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #151) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #154))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #151)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #151) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #156))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #151) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #157) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #160) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #163)) #("\n" 0 1 (:parent #163))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #160) #(" " 0 2 (:parent #164)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #164)) #("provides a route " 0 17 (:parent #164)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #164)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #164)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #164)) #("command). Given away by the reference to " 0 41 (:parent #164)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #164) #("Nix" 0 3 (:parent #174))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #164)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #164) #("Nix Binary Cache" 0 16 (:parent #176))) #(".\n" 0 2 (:parent #164))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #160) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #165))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #160)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #160) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #167))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #160))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #157) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #161) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #164)) #("\n" 0 1 (:parent #164))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #161) #(" " 0 2 (:parent #165)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #165) #("NAR (Nix Archive Format)" 0 24 (:parent #169))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #165)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #165) #("hello" 0 5 (:parent #171))) #("package.\n" 0 9 (:parent #165))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #161) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #166))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #161)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #161)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #161) #(" The result is composed of a few parts:\n" 0 41 (:parent #169))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #161) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #173))) :mode item :granularity nil :parent #170) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #173) #("the guix store path\n" 0 20 (:parent #176)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #174))) :mode item :granularity nil :parent #170) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #174) #("a hash uniquely identifying the store item\n" 0 43 (:parent #177)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #175))) :mode item :granularity nil :parent #170) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #175) #("the package-name and version, separated by dashes\n" 0 50 (:parent #178))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #161) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #171)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #171)) #(".\n" 0 2 (:parent #171))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #161))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #157) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #162) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #165)) #("\n" 0 1 (:parent #165))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #162) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #166)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #166)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #166)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #166)) #("file.\n" 0 6 (:parent #166))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #162)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #162)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #162) #(" If the package is not available, this would return a " 0 55 (:parent #169)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #169)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #169)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #169)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #169)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #169)) #("below.\n" 0 7 (:parent #169))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #162) #(" #+begin" 0 9 (:parent #170)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #170) #("src" 0 3 (:parent #174))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #170)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #170) #("nar" 0 3 (:parent #176))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #170)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #170) #("pass" 0 4 (:parent #178))) #("\" url \";\")\n \"client" 0 25 (:parent #170)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #170) #("body" 0 4 (:parent #180))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #170) #("buffer" 0 6 (:parent #181))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #170) #("size" 0 4 (:parent #182))) #("256k;\"\n" 0 7 (:parent #170)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #91) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #94) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #97)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #97) #("Guix channels" 0 13 (:parent #101))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #97)))) #45 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #96))) :mode nil :granularity nil :parent #91) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #96) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #99) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #102)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #102)) #("field of our " 0 13 (:parent #102)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #102)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #102))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #99)))))) #21)) . #0)) #("In order to run Cuirass via the " 0 32 (:parent #1)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #1)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #1)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #1)) #("as a " 0 5 (:parent #1)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #1) #("G-Expression" 0 12 (:parent #9))) #("that will return a list of\n" 0 27 (:parent #1)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #1) #("cuirass specifications" 0 22 (:parent #11))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #1))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #60))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #106))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #152))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #198) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #201)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #201)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #201)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #201)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #201)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #201)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #201)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #201)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #201)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #201)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #201) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #214))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #201) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #215))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #201) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #216))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #201) #("Earlier this year " 0 18 (:parent #217)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #217) #("I announced on the guix mailing list" 0 36 (:parent #221))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #217)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #202))) :mode nil :granularity nil :parent #198) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #202) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #205) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #208))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #205) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #209) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #212) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #215) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #218) #("Improved Build Diversity" 0 24 (:parent #221)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #215)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #209) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #213) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #216) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #219) #("Reduced Latency" 0 15 (:parent #222)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #216)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #209) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #214) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #217) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #220) #("Increased Resilience" 0 20 (:parent #223)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #217)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #209) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #215) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #218) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #221) #("Community Contribution" 0 22 (:parent #224)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #218))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #205) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #210)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #210) #("here" 0 4 (:parent #214))) #(".\n" 0 2 (:parent #210))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #203))) :mode nil :granularity nil :parent #198) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #203) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #206) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #209))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #206) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #210) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #213) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #216) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #219) #("Processor" 0 9 (:parent #222)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #216)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #210) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #214) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #217) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #220) #("RAM" 0 3 (:parent #223)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #217)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #210) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #215) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #218) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #221) #("Storage" 0 7 (:parent #224)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #218)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #210) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #216) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #219) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #222) #("Network" 0 7 (:parent #225)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #219)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #210) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #217) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #220) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #223) #("Location" 0 8 (:parent #226)))) #(": Memphis TN\n" 0 13 (:parent #220))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #206) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #211))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #206) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #212))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #206) #("For more details, see the " 0 26 (:parent #213)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #213) #("Specifications section" 0 22 (:parent #217))) #("of the Cuirass Manual.\n" 0 23 (:parent #213))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #206) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #214))))) #152)) #106 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #156))) :mode nil :granularity nil :parent #152) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #156) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #159) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #162)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #162) #("guix publish" 0 12 (:parent #166))) #(", which Guix provides the " 0 26 (:parent #162)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #162) #("guix-publish-service-type" 0 25 (:parent #168))) #(",\nwhich is used in the " 0 23 (:parent #162)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #162)) #("field of " 0 9 (:parent #162)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #162)) #("definition.\n" 0 12 (:parent #162))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #159)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #159) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #164))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #157))) :mode nil :granularity nil :parent #152) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #157) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #160) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #163))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #160) #("To anonymize nginx access logs, the " 0 36 (:parent #164)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #164) #("anonip-service-type" 0 19 (:parent #168))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #164)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #164)) #("is defined.\n" 0 12 (:parent #164))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #160)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #160) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #166))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #160)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #160) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #168)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #168)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #168))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #160)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #160) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #170)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #170)) #("field of our\n" 0 13 (:parent #170)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #170)) #("declaration.\n" 0 13 (:parent #170))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #160)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #158))) :mode nil :granularity nil :parent #152) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #158) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #161) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #164)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #162))) :mode nil :granularity nil :parent #158) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #162) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #165) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #168)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #168) #("letsencrypt" 0 11 (:parent #172))) #("via the " 0 8 (:parent #168)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #168) #("certbot" 0 7 (:parent #174))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #168)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #168) #("certbox-service-type" 0 20 (:parent #176))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #168)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #168)) #("field in our " 0 13 (:parent #168)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #168)) #("configuration.\n" 0 15 (:parent #168))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #165)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #165) #("This service references " 0 24 (:parent #170)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #170)) #(", which we define below. It sends " 0 34 (:parent #170)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #170)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #170))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #165)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #165) #("Next we define a function we will use later in the " 0 51 (:parent #172)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #172) #("Configure Nginx Server Blocks" 0 29 (:parent #176))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #172))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #165)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #163)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #163))) :mode nil :granularity nil :parent #158) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #163) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #166) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #169))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #166)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #166) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #171))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #166) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #172) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #175) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #178)) #("\n" 0 1 (:parent #178))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #175) #(" " 0 2 (:parent #179)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #179)) #("provides a route " 0 17 (:parent #179)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #179)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #179)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #179)) #("command). Given away by the reference to " 0 41 (:parent #179)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #179) #("Nix" 0 3 (:parent #189))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #179)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #179) #("Nix Binary Cache" 0 16 (:parent #191))) #(".\n" 0 2 (:parent #179))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #175) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #180))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #175)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #175) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #182))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #175))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #172) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #176) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #179)) #("\n" 0 1 (:parent #179))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #176) #(" " 0 2 (:parent #180)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #180) #("NAR (Nix Archive Format)" 0 24 (:parent #184))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #180)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #180) #("hello" 0 5 (:parent #186))) #("package.\n" 0 9 (:parent #180))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #176) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #181))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #176)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #176)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #176) #(" The result is composed of a few parts:\n" 0 41 (:parent #184))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #176) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #188))) :mode item :granularity nil :parent #185) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #188) #("the guix store path\n" 0 20 (:parent #191)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #189))) :mode item :granularity nil :parent #185) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #189) #("a hash uniquely identifying the store item\n" 0 43 (:parent #192)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #190))) :mode item :granularity nil :parent #185) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #190) #("the package-name and version, separated by dashes\n" 0 50 (:parent #193))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #176) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #186)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #186)) #(".\n" 0 2 (:parent #186))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #176))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #172) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #177) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #180)) #("\n" 0 1 (:parent #180))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #177) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #181)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #181)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #181)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #181)) #("file.\n" 0 6 (:parent #181))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #177)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #177)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #177) #(" If the package is not available, this would return a " 0 55 (:parent #184)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #184)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #184)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #184)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #184)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #184)) #("below.\n" 0 7 (:parent #184))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #177) #(" #+begin" 0 9 (:parent #185)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #185) #("src" 0 3 (:parent #189))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #185)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #185) #("nar" 0 3 (:parent #191))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #185)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #185) #("pass" 0 4 (:parent #193))) #("\" url \";\")\n \"client" 0 25 (:parent #185)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #185) #("body" 0 4 (:parent #195))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #185) #("buffer" 0 6 (:parent #196))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #185) #("size" 0 4 (:parent #197))) #("256k;\"\n" 0 7 (:parent #185)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #106) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #109) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #112)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #112) #("Guix channels" 0 13 (:parent #116))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #112)))) #60 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #111))) :mode nil :granularity nil :parent #106) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #111) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #114) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #117)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #117)) #("field of our " 0 13 (:parent #117)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #117)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #117))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #114)))))) #36)) . #0))) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #47))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #93))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #139))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #185) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #188)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #188)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #188)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #188)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #188)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #188)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #188)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #188)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #188)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #188)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #188) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #201))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #188) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #202))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #188) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #203))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #188) #("Earlier this year " 0 18 (:parent #204)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #204) #("I announced on the guix mailing list" 0 36 (:parent #208))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #204)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #189))) :mode nil :granularity nil :parent #185) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #189) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #192) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #195))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #192) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #196) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #199) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #202) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #205) #("Improved Build Diversity" 0 24 (:parent #208)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #202)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #196) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #200) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #203) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #206) #("Reduced Latency" 0 15 (:parent #209)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #203)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #196) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #201) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #204) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #207) #("Increased Resilience" 0 20 (:parent #210)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #204)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #196) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #202) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #205) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #208) #("Community Contribution" 0 22 (:parent #211)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #205))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #192) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #197)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #197) #("here" 0 4 (:parent #201))) #(".\n" 0 2 (:parent #197))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #190))) :mode nil :granularity nil :parent #185) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #190) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #193) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #196))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #193) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #200) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #203) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #206) #("Processor" 0 9 (:parent #209)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #203)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #201) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #204) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #207) #("RAM" 0 3 (:parent #210)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #204)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #202) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #205) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #208) #("Storage" 0 7 (:parent #211)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #205)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #203) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #206) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #209) #("Network" 0 7 (:parent #212)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #206)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #204) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #207) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #210) #("Location" 0 8 (:parent #213)))) #(": Memphis TN\n" 0 13 (:parent #207))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #193) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #198))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #193) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #199))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #193) #("For more details, see the " 0 26 (:parent #200)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #200) #("Specifications section" 0 22 (:parent #204))) #("of the Cuirass Manual.\n" 0 23 (:parent #200))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #193) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #201))))) #139)) #93 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #143))) :mode nil :granularity nil :parent #139) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #143) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #146) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #149)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #149) #("guix publish" 0 12 (:parent #153))) #(", which Guix provides the " 0 26 (:parent #149)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #149) #("guix-publish-service-type" 0 25 (:parent #155))) #(",\nwhich is used in the " 0 23 (:parent #149)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #149)) #("field of " 0 9 (:parent #149)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #149)) #("definition.\n" 0 12 (:parent #149))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #146)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #146) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #151))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #144))) :mode nil :granularity nil :parent #139) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #144) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #147) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #150))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #147) #("To anonymize nginx access logs, the " 0 36 (:parent #151)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #151) #("anonip-service-type" 0 19 (:parent #155))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #151)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #151)) #("is defined.\n" 0 12 (:parent #151))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #147)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #147) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #153))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #147)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #147) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #155)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #155)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #155))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #147)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #147) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #157)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #157)) #("field of our\n" 0 13 (:parent #157)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #157)) #("declaration.\n" 0 13 (:parent #157))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #147)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #145))) :mode nil :granularity nil :parent #139) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #145) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #148) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #151)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #149))) :mode nil :granularity nil :parent #145) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #149) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #152) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #155)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #155) #("letsencrypt" 0 11 (:parent #159))) #("via the " 0 8 (:parent #155)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #155) #("certbot" 0 7 (:parent #161))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #155)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #155) #("certbox-service-type" 0 20 (:parent #163))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #155)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #155)) #("field in our " 0 13 (:parent #155)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #155)) #("configuration.\n" 0 15 (:parent #155))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #152)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #152) #("This service references " 0 24 (:parent #157)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #157)) #(", which we define below. It sends " 0 34 (:parent #157)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #157)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #157))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #152)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #152) #("Next we define a function we will use later in the " 0 51 (:parent #159)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #159) #("Configure Nginx Server Blocks" 0 29 (:parent #163))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #159))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #152)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #150)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #150))) :mode nil :granularity nil :parent #145) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #150) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #153) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #156))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #153)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #153) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #158))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #153) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #159) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #162) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #165)) #("\n" 0 1 (:parent #165))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #162) #(" " 0 2 (:parent #166)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #166)) #("provides a route " 0 17 (:parent #166)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #166)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #166)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #166)) #("command). Given away by the reference to " 0 41 (:parent #166)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #166) #("Nix" 0 3 (:parent #176))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #166)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #166) #("Nix Binary Cache" 0 16 (:parent #178))) #(".\n" 0 2 (:parent #166))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #162) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #167))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #162)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #162) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #169))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #162))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #159) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #163) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #166)) #("\n" 0 1 (:parent #166))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #163) #(" " 0 2 (:parent #167)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #167) #("NAR (Nix Archive Format)" 0 24 (:parent #171))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #167)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #167) #("hello" 0 5 (:parent #173))) #("package.\n" 0 9 (:parent #167))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #163) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #168))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #163)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #163)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #163) #(" The result is composed of a few parts:\n" 0 41 (:parent #171))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #163) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #175))) :mode item :granularity nil :parent #172) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #175) #("the guix store path\n" 0 20 (:parent #178)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #176))) :mode item :granularity nil :parent #172) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #176) #("a hash uniquely identifying the store item\n" 0 43 (:parent #179)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #177))) :mode item :granularity nil :parent #172) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #177) #("the package-name and version, separated by dashes\n" 0 50 (:parent #180))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #163) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #173)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #173)) #(".\n" 0 2 (:parent #173))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #163))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #159) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #164) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #167)) #("\n" 0 1 (:parent #167))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #164) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #168)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #168)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #168)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #168)) #("file.\n" 0 6 (:parent #168))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #164)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #164)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #164) #(" If the package is not available, this would return a " 0 55 (:parent #171)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #171)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #171)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #171)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #171)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #171)) #("below.\n" 0 7 (:parent #171))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #164) #(" #+begin" 0 9 (:parent #172)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #172) #("src" 0 3 (:parent #176))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #172)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #172) #("nar" 0 3 (:parent #178))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #172)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #172) #("pass" 0 4 (:parent #180))) #("\" url \";\")\n \"client" 0 25 (:parent #172)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #172) #("body" 0 4 (:parent #182))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #172) #("buffer" 0 6 (:parent #183))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #172) #("size" 0 4 (:parent #184))) #("256k;\"\n" 0 7 (:parent #172)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #93) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #96) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #99)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #99) #("Guix channels" 0 13 (:parent #103))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #99)))) #47 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #98))) :mode nil :granularity nil :parent #93) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #98) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #101) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #104)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #104)) #("field of our " 0 13 (:parent #104)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #104)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #104))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #101)))))) #23)) . #0)) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #3)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #3)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #3)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #3) #("Cuirass specification" 0 21 (:parent #9))) #("\ndocumentation for more details.\n" 0 33 (:parent #3))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #48))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #94))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #140))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #186) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #189)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #189)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #189)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #189) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #202))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #189) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #203))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #189) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #204))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #189) #("Earlier this year " 0 18 (:parent #205)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #205) #("I announced on the guix mailing list" 0 36 (:parent #209))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #205)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #190))) :mode nil :granularity nil :parent #186) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #190) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #193) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #196))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #193) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #200) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #203) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #206) #("Improved Build Diversity" 0 24 (:parent #209)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #203)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #201) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #204) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #207) #("Reduced Latency" 0 15 (:parent #210)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #204)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #202) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #205) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #208) #("Increased Resilience" 0 20 (:parent #211)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #205)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #197) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #203) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #206) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #209) #("Community Contribution" 0 22 (:parent #212)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #206))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #193) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #198)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #198) #("here" 0 4 (:parent #202))) #(".\n" 0 2 (:parent #198))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #191))) :mode nil :granularity nil :parent #186) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #191) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #194) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #197))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #194) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #201) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #204) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #207) #("Processor" 0 9 (:parent #210)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #204)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #202) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #205) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #208) #("RAM" 0 3 (:parent #211)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #205)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #203) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #206) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #209) #("Storage" 0 7 (:parent #212)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #206)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #204) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #207) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #210) #("Network" 0 7 (:parent #213)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #207)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #198) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #205) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #208) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #211) #("Location" 0 8 (:parent #214)))) #(": Memphis TN\n" 0 13 (:parent #208))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #194) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #199))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #194) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #200))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #194) #("For more details, see the " 0 26 (:parent #201)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #201) #("Specifications section" 0 22 (:parent #205))) #("of the Cuirass Manual.\n" 0 23 (:parent #201))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #194) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #202))))) #140)) #94 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #144))) :mode nil :granularity nil :parent #140) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #144) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #147) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #150)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #150) #("guix publish" 0 12 (:parent #154))) #(", which Guix provides the " 0 26 (:parent #150)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #150) #("guix-publish-service-type" 0 25 (:parent #156))) #(",\nwhich is used in the " 0 23 (:parent #150)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #150)) #("field of " 0 9 (:parent #150)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #150)) #("definition.\n" 0 12 (:parent #150))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #147)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #147) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #152))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #145))) :mode nil :granularity nil :parent #140) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #145) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #148) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #151))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #148) #("To anonymize nginx access logs, the " 0 36 (:parent #152)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #152) #("anonip-service-type" 0 19 (:parent #156))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #152)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #152)) #("is defined.\n" 0 12 (:parent #152))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #148)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #148) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #154))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #148)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #148) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #156)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #156)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #156))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #148)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #148) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #158)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #158)) #("field of our\n" 0 13 (:parent #158)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #158)) #("declaration.\n" 0 13 (:parent #158))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #148)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #146))) :mode nil :granularity nil :parent #140) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #146) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #149) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #152)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #150))) :mode nil :granularity nil :parent #146) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #150) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #153) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #156)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #156) #("letsencrypt" 0 11 (:parent #160))) #("via the " 0 8 (:parent #156)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #156) #("certbot" 0 7 (:parent #162))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #156)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #156) #("certbox-service-type" 0 20 (:parent #164))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #156)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #156)) #("field in our " 0 13 (:parent #156)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #156)) #("configuration.\n" 0 15 (:parent #156))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #153)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #153) #("This service references " 0 24 (:parent #158)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #158)) #(", which we define below. It sends " 0 34 (:parent #158)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #158)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #158))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #153)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #153) #("Next we define a function we will use later in the " 0 51 (:parent #160)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #160) #("Configure Nginx Server Blocks" 0 29 (:parent #164))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #160))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #153)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #151)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #151))) :mode nil :granularity nil :parent #146) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #151) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #154) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #157))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #154)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #154) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #159))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #154) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #160) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #163) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #166)) #("\n" 0 1 (:parent #166))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #163) #(" " 0 2 (:parent #167)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #167)) #("provides a route " 0 17 (:parent #167)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #167)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #167)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #167)) #("command). Given away by the reference to " 0 41 (:parent #167)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #167) #("Nix" 0 3 (:parent #177))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #167)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #167) #("Nix Binary Cache" 0 16 (:parent #179))) #(".\n" 0 2 (:parent #167))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #163) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #168))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #163)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #163) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #170))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #163))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #160) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #164) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #167)) #("\n" 0 1 (:parent #167))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #164) #(" " 0 2 (:parent #168)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #168) #("NAR (Nix Archive Format)" 0 24 (:parent #172))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #168)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #168) #("hello" 0 5 (:parent #174))) #("package.\n" 0 9 (:parent #168))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #164) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #169))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #164)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #164)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #164) #(" The result is composed of a few parts:\n" 0 41 (:parent #172))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #164) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #176))) :mode item :granularity nil :parent #173) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #176) #("the guix store path\n" 0 20 (:parent #179)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #177))) :mode item :granularity nil :parent #173) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #177) #("a hash uniquely identifying the store item\n" 0 43 (:parent #180)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #178))) :mode item :granularity nil :parent #173) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #178) #("the package-name and version, separated by dashes\n" 0 50 (:parent #181))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #164) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #174)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #174)) #(".\n" 0 2 (:parent #174))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #164))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #160) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #165) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #168)) #("\n" 0 1 (:parent #168))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #165) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #169)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #169)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #169)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #169)) #("file.\n" 0 6 (:parent #169))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #165)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #165)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #165) #(" If the package is not available, this would return a " 0 55 (:parent #172)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #172)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #172)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #172)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #172)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #172)) #("below.\n" 0 7 (:parent #172))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #165) #(" #+begin" 0 9 (:parent #173)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #173) #("src" 0 3 (:parent #177))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #173)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #173) #("nar" 0 3 (:parent #179))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #173)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #173) #("pass" 0 4 (:parent #181))) #("\" url \";\")\n \"client" 0 25 (:parent #173)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #173) #("body" 0 4 (:parent #183))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #173) #("buffer" 0 6 (:parent #184))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #173) #("size" 0 4 (:parent #185))) #("256k;\"\n" 0 7 (:parent #173)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #94) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #97) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #100)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #100) #("Guix channels" 0 13 (:parent #104))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #100)))) #48 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #99))) :mode nil :granularity nil :parent #94) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #99) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #102) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #105)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #105)) #("field of our " 0 13 (:parent #105)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #105)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #105))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #102)))))) #24)) . #0)) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #4)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #4) #("Guix Configuration as a Channel" 0 31 (:parent #8))) #(".\n" 0 2 (:parent #4)))) "")
org-export-data((section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #24))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #70))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #116))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #162) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #165)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #165)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #165) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #178))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #165) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #179))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #165) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #180))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #165) #("Earlier this year " 0 18 (:parent #181)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #181) #("I announced on the guix mailing list" 0 36 (:parent #185))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #181)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #166))) :mode nil :granularity nil :parent #162) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #166) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #169) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #172))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #169) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #173) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #176) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #179) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #182) #("Improved Build Diversity" 0 24 (:parent #185)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #179)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #173) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #177) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #180) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #183) #("Reduced Latency" 0 15 (:parent #186)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #180)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #173) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #178) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #181) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #184) #("Increased Resilience" 0 20 (:parent #187)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #181)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #173) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #179) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #182) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #185) #("Community Contribution" 0 22 (:parent #188)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #182))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #169) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #174)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #174) #("here" 0 4 (:parent #178))) #(".\n" 0 2 (:parent #174))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #167))) :mode nil :granularity nil :parent #162) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #167) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #170) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #173))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #170) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #177) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #180) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #183) #("Processor" 0 9 (:parent #186)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #180)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #178) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #181) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #184) #("RAM" 0 3 (:parent #187)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #181)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #179) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #182) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #185) #("Storage" 0 7 (:parent #188)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #182)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #180) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #183) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #186) #("Network" 0 7 (:parent #189)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #183)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #181) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #184) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #187) #("Location" 0 8 (:parent #190)))) #(": Memphis TN\n" 0 13 (:parent #184))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #170) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #175))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #170) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #176))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #170) #("For more details, see the " 0 26 (:parent #177)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #177) #("Specifications section" 0 22 (:parent #181))) #("of the Cuirass Manual.\n" 0 23 (:parent #177))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #170) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #178))))) #116)) #70 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #120))) :mode nil :granularity nil :parent #116) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #120) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #123) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #126)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #126) #("guix publish" 0 12 (:parent #130))) #(", which Guix provides the " 0 26 (:parent #126)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #126) #("guix-publish-service-type" 0 25 (:parent #132))) #(",\nwhich is used in the " 0 23 (:parent #126)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #126)) #("field of " 0 9 (:parent #126)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #126)) #("definition.\n" 0 12 (:parent #126))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #123)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #123) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #128))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #121))) :mode nil :granularity nil :parent #116) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #121) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #124) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #127))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #124) #("To anonymize nginx access logs, the " 0 36 (:parent #128)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #128) #("anonip-service-type" 0 19 (:parent #132))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #128)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #128)) #("is defined.\n" 0 12 (:parent #128))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #124)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #124) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #130))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #124)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #124) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #132)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #132)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #132))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #124)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #124) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #134)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #134)) #("field of our\n" 0 13 (:parent #134)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #134)) #("declaration.\n" 0 13 (:parent #134))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #124)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #122))) :mode nil :granularity nil :parent #116) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #122) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #125) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #128)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #126))) :mode nil :granularity nil :parent #122) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #126) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #129) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #132)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #132) #("letsencrypt" 0 11 (:parent #136))) #("via the " 0 8 (:parent #132)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #132) #("certbot" 0 7 (:parent #138))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #132)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #132) #("certbox-service-type" 0 20 (:parent #140))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #132)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #132)) #("field in our " 0 13 (:parent #132)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #132)) #("configuration.\n" 0 15 (:parent #132))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #129)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #129) #("This service references " 0 24 (:parent #134)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #134)) #(", which we define below. It sends " 0 34 (:parent #134)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #134)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #134))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #129)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #129) #("Next we define a function we will use later in the " 0 51 (:parent #136)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #136) #("Configure Nginx Server Blocks" 0 29 (:parent #140))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #136))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #129)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #127)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #127))) :mode nil :granularity nil :parent #122) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #127) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #130) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #133))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #130)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #130) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #135))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #130) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #136) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #139) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #142)) #("\n" 0 1 (:parent #142))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #139) #(" " 0 2 (:parent #143)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #143)) #("provides a route " 0 17 (:parent #143)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #143)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #143)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #143)) #("command). Given away by the reference to " 0 41 (:parent #143)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #143) #("Nix" 0 3 (:parent #153))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #143)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #143) #("Nix Binary Cache" 0 16 (:parent #155))) #(".\n" 0 2 (:parent #143))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #139) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #144))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #139)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #139) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #146))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #139))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #136) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #140) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #143)) #("\n" 0 1 (:parent #143))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #140) #(" " 0 2 (:parent #144)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #144) #("NAR (Nix Archive Format)" 0 24 (:parent #148))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #144)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #144) #("hello" 0 5 (:parent #150))) #("package.\n" 0 9 (:parent #144))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #140) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #145))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #140)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #140)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #140) #(" The result is composed of a few parts:\n" 0 41 (:parent #148))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #140) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #152))) :mode item :granularity nil :parent #149) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #152) #("the guix store path\n" 0 20 (:parent #155)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #153))) :mode item :granularity nil :parent #149) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #153) #("a hash uniquely identifying the store item\n" 0 43 (:parent #156)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #154))) :mode item :granularity nil :parent #149) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #154) #("the package-name and version, separated by dashes\n" 0 50 (:parent #157))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #140) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #150)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #150)) #(".\n" 0 2 (:parent #150))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #140))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #136) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #141) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #144)) #("\n" 0 1 (:parent #144))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #141) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #145)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #145)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #145)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #145)) #("file.\n" 0 6 (:parent #145))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #141)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #141)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #141) #(" If the package is not available, this would return a " 0 55 (:parent #148)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #148)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #148)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #148)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #148)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #148)) #("below.\n" 0 7 (:parent #148))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #141) #(" #+begin" 0 9 (:parent #149)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #149) #("src" 0 3 (:parent #153))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #149)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #149) #("nar" 0 3 (:parent #155))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #149)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #149) #("pass" 0 4 (:parent #157))) #("\" url \";\")\n \"client" 0 25 (:parent #149)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #149) #("body" 0 4 (:parent #159))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #149) #("buffer" 0 6 (:parent #160))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #149) #("size" 0 4 (:parent #161))) #("256k;\"\n" 0 7 (:parent #149)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #70) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #73) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #76)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #76) #("Guix channels" 0 13 (:parent #80))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #76)))) #24 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #75))) :mode nil :granularity nil :parent #70) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #75) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #78) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #81)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #81)) #("field of our " 0 13 (:parent #81)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #81)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #81))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #78)))))) #0)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #0) #("In order to run Cuirass via the " 0 32 (:parent #3)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #3)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #3)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #3)) #("as a " 0 5 (:parent #3)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #3) #("G-Expression" 0 12 (:parent #11))) #("that will return a list of\n" 0 27 (:parent #3)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #3) #("cuirass specifications" 0 22 (:parent #13))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #3))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #0)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #0) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #5)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #5)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #5)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #5) #("Cuirass specification" 0 21 (:parent #11))) #("\ndocumentation for more details.\n" 0 33 (:parent #5))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #0) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #6)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #6) #("Guix Configuration as a Channel" 0 31 (:parent #10))) #(".\n" 0 2 (:parent #6)))) (:export-options (body-only) :back-end #s(org-export-backend :name html :parent nil :transcoders ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :options ((:html-doctype "HTML_DOCTYPE" nil org-html-doctype) (:html-container "HTML_CONTAINER" nil org-html-container-element) (:html-content-class "HTML_CONTENT_CLASS" nil org-html-content-class) (:description "DESCRIPTION" nil nil newline) (:keywords "KEYWORDS" nil nil space) (:html-html5-fancy nil "html5-fancy" org-html-html5-fancy) (:html-link-use-abs-url nil "html-link-use-abs-url" org-html-link-use-abs-url) (:html-link-home "HTML_LINK_HOME" nil org-html-link-home) (:html-link-up "HTML_LINK_UP" nil org-html-link-up) (:html-mathjax "HTML_MATHJAX" nil "" space) (:html-equation-reference-format "HTML_EQUATION_REFERENCE_FORMAT" nil org-html-equation-reference-format t) (:html-postamble nil "html-postamble" org-html-postamble) (:html-preamble nil "html-preamble" org-html-preamble) (:html-head "HTML_HEAD" nil org-html-head newline) (:html-head-extra "HTML_HEAD_EXTRA" nil org-html-head-extra newline) (:subtitle "SUBTITLE" nil nil parse) (:html-head-include-default-style nil "html-style" org-html-head-include-default-style) (:html-head-include-scripts nil "html-scripts" org-html-head-include-scripts) (:html-allow-name-attribute-in-anchors nil nil org-html-allow-name-attribute-in-anchors) (:html-divs nil nil org-html-divs) (:html-checkbox-type nil nil org-html-checkbox-type) (:html-extension nil nil org-html-extension) (:html-footnote-format nil nil org-html-footnote-format) (:html-footnote-separator nil nil org-html-footnote-separator) (:html-footnotes-section nil nil org-html-footnotes-section) (:html-format-drawer-function nil nil org-html-format-drawer-function) (:html-format-headline-function nil nil org-html-format-headline-function) (:html-format-inlinetask-function nil nil org-html-format-inlinetask-function) (:html-home/up-format nil nil org-html-home/up-format) (:html-indent nil nil org-html-indent) (:html-infojs-options nil nil org-html-infojs-options) (:html-infojs-template nil nil org-html-infojs-template) (:html-inline-image-rules nil nil org-html-inline-image-rules) (:html-link-org-files-as-html nil nil org-html-link-org-files-as-html) (:html-mathjax-options nil nil org-html-mathjax-options) (:html-mathjax-template nil nil org-html-mathjax-template) (:html-metadata-timestamp-format nil nil org-html-metadata-timestamp-format) (:html-postamble-format nil nil org-html-postamble-format) (:html-preamble-format nil nil org-html-preamble-format) (:html-prefer-user-labels nil nil org-html-prefer-user-labels) (:html-self-link-headlines nil nil org-html-self-link-headlines) (:html-table-align-individual-fields nil nil org-html-table-align-individual-fields) (:html-table-caption-above nil nil org-html-table-caption-above) (:html-table-data-tags nil nil org-html-table-data-tags) (:html-table-header-tags nil nil org-html-table-header-tags) (:html-table-use-header-tags-for-first-column nil nil org-html-table-use-header-tags-for-first-column) (:html-tag-class-prefix nil nil org-html-tag-class-prefix) (:html-text-markup-alist nil nil org-html-text-markup-alist) (:html-todo-kwd-class-prefix nil nil org-html-todo-kwd-class-prefix) (:html-toplevel-hlevel nil nil org-html-toplevel-hlevel) (:html-use-infojs nil nil org-html-use-infojs) (:html-validation-link nil nil org-html-validation-link) (:html-viewport nil nil org-html-viewport) (:html-inline-images nil nil org-html-inline-images) (:html-table-attributes nil nil org-html-table-default-attributes) (:html-table-row-open-tag nil nil org-html-table-row-open-tag) (:html-table-row-close-tag nil nil org-html-table-row-close-tag) (:html-xml-declaration nil nil org-html-xml-declaration) (:html-wrap-src-lines nil nil org-html-wrap-src-lines) (:html-klipsify-src nil nil org-html-klipsify-src) (:html-klipse-css nil nil org-html-klipse-css) (:html-klipse-js nil nil org-html-klipse-js) (:html-klipse-selection-script nil nil org-html-klipse-selection-script) (:infojs-opt "INFOJS_OPT" nil nil) (:creator "CREATOR" nil org-html-creator-string) (:with-latex nil "tex" org-html-with-latex) (:latex-header "LATEX_HEADER" nil nil newline)) :filters ((:filter-options . org-html-infojs-install-script) (:filter-parse-tree . org-html-image-link-filter) (:filter-final-output . org-html-final-function)) :blocks nil :menu (104 "Export to HTML" ((72 "As HTML buffer" org-html-export-as-html) (104 "As HTML file" org-html-export-to-html) (111 "As HTML file and open" (lambda (a s v b) (if a (org-html-export-to-html t s v b) (org-open-file (org-html-export-to-html nil s v b)))))))) :translate-alist ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data # :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil :html-divs ((preamble "div" "preamble") (content "div" "content") (postamble "div" "postamble")) :html-checkbox-type ascii :html-extension "html" :html-footnote-format "%s" :html-footnote-separator ", " :html-footnotes-section ") :html-format-headline-function org-html-format-headline-default-function :html-format-inlinetask-function org-html-format-inlinetask-default-function :html-home/up-format "" :html-indent nil :html-infojs-options ((path . "https://orgmode.org/org-info.js") (view . "info") (toc . :with-toc) (ftoc . "0") (tdepth . "max") (sdepth . "max") (mouse . "underline") (buttons . "0") (ltoc . "1") (up . :html-link-up) (home . :html-link-home)) :html-infojs-template "\n\n" :html-inline-image-rules (("file" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("http" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("https" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)")) :html-link-org-files-as-html t :html-mathjax-options ((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js") (scale 1.0) (align "center") (font "mathjax-modern") (overflow "overflow") (tags "ams") (indent "0em") (multlinewidth "85%") (tagindent ".8em") (tagside "right")) :html-mathjax-template "\n\n" :html-metadata-timestamp-format "%Y-%m-%d %a %H:%M" :html-postamble-format (("en" " \n" . " ") :html-table-header-tags ("" . " ") :html-table-use-header-tags-for-first-column nil :html-tag-class-prefix "" :html-text-markup-alist ((bold . "%s") (code . "%s") (underline . "%s") (verbatim . "" :html-table-row-close-tag " " :html-xml-declaration (("html" . "") ("php" . "\"; ?>")) :html-wrap-src-lines nil :html-klipsify-src nil :html-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css" :html-klipse-js "https://storage.googleapis.com/app.klipse.tech/plugin_prod/js/klipse_plugin.min.js" :html-klipse-selection-script "window.klipse_settings = {selector_eval_html: '.src-html',\n selector_eval_js: '.src-js',\n selector_eval_python_client: '.src-python',\n selector_eval_scheme: '.src-scheme',\n selector: '.src-clojure',\n selector_eval_ruby: '.src-ruby'};" :infojs-opt nil :creator "Emacs 29.4 (Org mode 9.6.15)" :with-latex t :latex-header "\\usepackage[margin=1.5cm]{geometry}\n\\usepackage{xcolor}\n\\definecolor{link}{HTML}{506060}\n\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :title (#("Setup of a Simple Guix Build Farm and Substitute Server" 0 55 (:parent #148))) :date nil :author (#("Collin J. Doering" 0 17 (:parent #152))) :email "unknown@genenetwork-development" :language "en" :select-tags ("export") :exclude-tags ("noexport") :headline-levels 3 :preserve-breaks nil :section-numbers nil :time-stamp-file t :with-archived-trees headline :with-author t :with-broken-links nil :with-clocks nil :with-creator nil :with-date t :with-drawers (not "LOGBOOK") :with-email nil :with-emphasize t :with-entities t :with-fixed-width t :with-footnotes t :with-inlinetasks t :with-planning nil :with-priority nil :with-properties nil :with-smart-quotes nil :with-special-strings t :with-statistics-cookies t :with-sub-superscript t :with-toc nil :with-tables t :with-tags t :with-tasks t :with-timestamps t :with-title t :with-todo-keywords t :cite-export (basic nil nil) :bibliography nil :filter-body nil :filter-bold nil :filter-babel-call nil :filter-center-block nil :filter-clock nil :filter-code nil :filter-diary-sexp nil :filter-drawer nil :filter-dynamic-block nil :filter-entity nil :filter-example-block nil :filter-export-block nil :filter-export-snippet nil :filter-final-output (org-html-final-function) :filter-fixed-width nil :filter-footnote-definition nil :filter-footnote-reference nil :filter-headline nil :filter-horizontal-rule nil :filter-inline-babel-call nil :filter-inline-src-block nil :filter-inlinetask nil :filter-italic nil :filter-item nil :filter-keyword nil :filter-latex-environment nil :filter-latex-fragment nil :filter-line-break nil :filter-link nil :filter-node-property nil :filter-options (org-html-infojs-install-script) :filter-paragraph nil :filter-parse-tree (org-html-image-link-filter) :filter-plain-list nil :filter-plain-text nil :filter-planning nil :filter-property-drawer nil :filter-quote-block nil :filter-radio-target nil :filter-section nil :filter-special-block nil :filter-src-block nil :filter-statistics-cookie nil :filter-strike-through nil :filter-subscript nil :filter-superscript nil :filter-table nil :filter-table-cell nil :filter-table-row nil :filter-target nil :filter-timestamp nil :filter-underline nil :filter-verbatim nil :filter-verse-block nil :ignore-list nil :parse-tree (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #338) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #341)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #341)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #341) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #354))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #341) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #355))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #341) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #356))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #341) #("Earlier this year " 0 18 (:parent #357)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #357) #("I announced on the guix mailing list" 0 36 (:parent #361))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #357)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #342))) :mode nil :granularity nil :parent #338) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #342) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #345) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #348))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #345) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #352) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #355) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #358) #("Improved Build Diversity" 0 24 (:parent #361)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #355)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #353) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #356) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #359) #("Reduced Latency" 0 15 (:parent #362)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #356)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #354) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #357) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #360) #("Increased Resilience" 0 20 (:parent #363)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #357)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #355) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #358) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #361) #("Community Contribution" 0 22 (:parent #364)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #358))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #345) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #350)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #350) #("here" 0 4 (:parent #354))) #(".\n" 0 2 (:parent #350))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #343))) :mode nil :granularity nil :parent #338) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #343) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #346) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #349))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #346) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #353) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #356) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #359) #("Processor" 0 9 (:parent #362)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #356)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #354) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #357) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #360) #("RAM" 0 3 (:parent #363)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #357)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #355) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #358) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #361) #("Storage" 0 7 (:parent #364)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #358)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #356) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #359) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #362) #("Network" 0 7 (:parent #365)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #359)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #357) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #360) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #363) #("Location" 0 8 (:parent #366)))) #(": Memphis TN\n" 0 13 (:parent #360))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #346) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #351))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #346) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #352))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #346) #("For more details, see the " 0 26 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #353) #("Specifications section" 0 22 (:parent #357))) #("of the Cuirass Manual.\n" 0 23 (:parent #353))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #346) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #354))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #344))) :mode nil :granularity nil :parent #338) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #347))) :mode section :granularity nil :parent #344) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #347) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #350) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #353) #("Guix channels" 0 13 (:parent #357))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #353)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #351))) :mode nil :granularity nil :parent #347) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #351) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #354) #("In order to run Cuirass via the " 0 32 (:parent #357)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #357)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #357)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #357)) #("as a " 0 5 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #357) #("G-Expression" 0 12 (:parent #365))) #("that will return a list of\n" 0 27 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #357) #("cuirass specifications" 0 22 (:parent #367))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #357))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #354)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #354) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #359)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #359)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #359)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #359) #("Cuirass specification" 0 21 (:parent #365))) #("\ndocumentation for more details.\n" 0 33 (:parent #359))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #354) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #360)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #360) #("Guix Configuration as a Channel" 0 31 (:parent #364))) #(".\n" 0 2 (:parent #360))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #352))) :mode nil :granularity nil :parent #347) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #352) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #355) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #358)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #358)) #("field of our " 0 13 (:parent #358)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #358)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #355))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #348))) :mode nil :granularity nil :parent #344) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #348) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #351) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #354)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #354) #("guix publish" 0 12 (:parent #358))) #(", which Guix provides the " 0 26 (:parent #354)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #354) #("guix-publish-service-type" 0 25 (:parent #360))) #(",\nwhich is used in the " 0 23 (:parent #354)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #354)) #("field of " 0 9 (:parent #354)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #354)) #("definition.\n" 0 12 (:parent #354))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #351)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #351) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #356))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #349))) :mode nil :granularity nil :parent #344) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #349) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #352) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #355))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #352) #("To anonymize nginx access logs, the " 0 36 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #356) #("anonip-service-type" 0 19 (:parent #360))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #356)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #356)) #("is defined.\n" 0 12 (:parent #356))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #352) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #352) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #360)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #360)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #352)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #352) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #362)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #362)) #("field of our\n" 0 13 (:parent #362)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #362)) #("declaration.\n" 0 13 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #352)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #350))) :mode nil :granularity nil :parent #344) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #350) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #353) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #356)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #354) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #357) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #360)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #360) #("letsencrypt" 0 11 (:parent #364))) #("via the " 0 8 (:parent #360)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #360) #("certbot" 0 7 (:parent #366))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #360) #("certbox-service-type" 0 20 (:parent #368))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #360)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #360)) #("field in our " 0 13 (:parent #360)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #360)) #("configuration.\n" 0 15 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #357) #("This service references " 0 24 (:parent #362)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #362)) #(", which we define below. It sends " 0 34 (:parent #362)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #362)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #357) #("Next we define a function we will use later in the " 0 51 (:parent #364)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #364) #("Configure Nginx Server Blocks" 0 29 (:parent #368))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #364))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #357)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #355)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #355) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #358) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #358)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #358) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #363))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #358) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #367) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #370)) #("\n" 0 1 (:parent #370))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #367) #(" " 0 2 (:parent #371)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #371)) #("provides a route " 0 17 (:parent #371)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #371)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #371)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #371)) #("command). Given away by the reference to " 0 41 (:parent #371)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #371) #("Nix" 0 3 (:parent #381))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #371)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #371) #("Nix Binary Cache" 0 16 (:parent #383))) #(".\n" 0 2 (:parent #371))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #367) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #372))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #367)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #367) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #374))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #367))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #368) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #371)) #("\n" 0 1 (:parent #371))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #368) #(" " 0 2 (:parent #372)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #372) #("NAR (Nix Archive Format)" 0 24 (:parent #376))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #372)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #372) #("hello" 0 5 (:parent #378))) #("package.\n" 0 9 (:parent #372))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #368) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #368)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #368)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #368) #(" The result is composed of a few parts:\n" 0 41 (:parent #376))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #368) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #380))) :mode item :granularity nil :parent #377) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #380) #("the guix store path\n" 0 20 (:parent #383)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #381))) :mode item :granularity nil :parent #377) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #381) #("a hash uniquely identifying the store item\n" 0 43 (:parent #384)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #382))) :mode item :granularity nil :parent #377) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #382) #("the package-name and version, separated by dashes\n" 0 50 (:parent #385))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #368) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #378)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #378)) #(".\n" 0 2 (:parent #378))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #368))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #369) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #372)) #("\n" 0 1 (:parent #372))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #369) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #373)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #373)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #373)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #373)) #("file.\n" 0 6 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #369)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #369)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #369) #(" If the package is not available, this would return a " 0 55 (:parent #376)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #376)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #376)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #376)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #376)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #376)) #("below.\n" 0 7 (:parent #376))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #369) #(" #+begin" 0 9 (:parent #377)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #377) #("src" 0 3 (:parent #381))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #377)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #377) #("nar" 0 3 (:parent #383))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #377)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #377) #("pass" 0 4 (:parent #385))) #("\" url \";\")\n \"client" 0 25 (:parent #377)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #377) #("body" 0 4 (:parent #387))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #377) #("buffer" 0 6 (:parent #388))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #377) #("size" 0 4 (:parent #389))) #("256k;\"\n" 0 7 (:parent #377)))))))))) :headline-offset 0 :headline-numbering nil :id-alist nil :citations nil :internal-references (("org1d65611" headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #350))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #396))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #442) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #445)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #445)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #445) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #458))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #445) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #459))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #445) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #460))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #445) #("Earlier this year " 0 18 (:parent #461)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #461) #("I announced on the guix mailing list" 0 36 (:parent #465))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #461)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #446))) :mode nil :granularity nil :parent #442) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #446) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #449) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #452))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #449) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #456) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #459) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #462) #("Improved Build Diversity" 0 24 (:parent #465)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #459)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #457) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #460) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #463) #("Reduced Latency" 0 15 (:parent #466)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #460)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #458) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #461) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #464) #("Increased Resilience" 0 20 (:parent #467)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #461)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #459) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #462) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #465) #("Community Contribution" 0 22 (:parent #468)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #462))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #449) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #454)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #454) #("here" 0 4 (:parent #458))) #(".\n" 0 2 (:parent #454))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #447))) :mode nil :granularity nil :parent #442) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #447) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #450) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #453))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #450) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #457) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #460) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #463) #("Processor" 0 9 (:parent #466)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #460)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #458) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #461) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #464) #("RAM" 0 3 (:parent #467)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #461)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #459) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #462) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #465) #("Storage" 0 7 (:parent #468)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #462)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #460) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #463) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #466) #("Network" 0 7 (:parent #469)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #463)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #461) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #464) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #467) #("Location" 0 8 (:parent #470)))) #(": Memphis TN\n" 0 13 (:parent #464))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #450) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #455))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #450) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #456))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #450) #("For more details, see the " 0 26 (:parent #457)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #457) #("Specifications section" 0 22 (:parent #461))) #("of the Cuirass Manual.\n" 0 23 (:parent #457))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #450) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #458))))) #396)) #350 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #400))) :mode nil :granularity nil :parent #396) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #400) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #403) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #406)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #406) #("guix publish" 0 12 (:parent #410))) #(", which Guix provides the " 0 26 (:parent #406)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #406) #("guix-publish-service-type" 0 25 (:parent #412))) #(",\nwhich is used in the " 0 23 (:parent #406)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #406)) #("field of " 0 9 (:parent #406)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #406)) #("definition.\n" 0 12 (:parent #406))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #403)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #403) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #408))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #401))) :mode nil :granularity nil :parent #396) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #401) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #404) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #407))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #404) #("To anonymize nginx access logs, the " 0 36 (:parent #408)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #408) #("anonip-service-type" 0 19 (:parent #412))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #408)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #408)) #("is defined.\n" 0 12 (:parent #408))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #404) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #410))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #404) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #412)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #412)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #404)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #404) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #414)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #414)) #("field of our\n" 0 13 (:parent #414)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #414)) #("declaration.\n" 0 13 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #404)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #402))) :mode nil :granularity nil :parent #396) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #402) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #405) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #408)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #406))) :mode nil :granularity nil :parent #402) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #406) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #409) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #412)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #412) #("letsencrypt" 0 11 (:parent #416))) #("via the " 0 8 (:parent #412)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #412) #("certbot" 0 7 (:parent #418))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #412)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #412) #("certbox-service-type" 0 20 (:parent #420))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #412)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #412)) #("field in our " 0 13 (:parent #412)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #412)) #("configuration.\n" 0 15 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #409) #("This service references " 0 24 (:parent #414)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #414)) #(", which we define below. It sends " 0 34 (:parent #414)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #414)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #409) #("Next we define a function we will use later in the " 0 51 (:parent #416)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #416) #("Configure Nginx Server Blocks" 0 29 (:parent #420))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #416))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #409)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #407)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #407) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #410) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #413))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #410)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #410) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #415))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #419) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #422)) #("\n" 0 1 (:parent #422))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #419) #(" " 0 2 (:parent #423)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #423)) #("provides a route " 0 17 (:parent #423)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #423)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #423)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #423)) #("command). Given away by the reference to " 0 41 (:parent #423)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #423) #("Nix" 0 3 (:parent #433))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #423)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #423) #("Nix Binary Cache" 0 16 (:parent #435))) #(".\n" 0 2 (:parent #423))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #419) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #424))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #419)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #419) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #419))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #420) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #423)) #("\n" 0 1 (:parent #423))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #420) #(" " 0 2 (:parent #424)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #424) #("NAR (Nix Archive Format)" 0 24 (:parent #428))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #424)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #424) #("hello" 0 5 (:parent #430))) #("package.\n" 0 9 (:parent #424))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #420) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #420)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #420)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #420) #(" The result is composed of a few parts:\n" 0 41 (:parent #428))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #420) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #432))) :mode item :granularity nil :parent #429) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #432) #("the guix store path\n" 0 20 (:parent #435)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #433))) :mode item :granularity nil :parent #429) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #433) #("a hash uniquely identifying the store item\n" 0 43 (:parent #436)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #434))) :mode item :granularity nil :parent #429) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #434) #("the package-name and version, separated by dashes\n" 0 50 (:parent #437))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #420) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #430)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #430)) #(".\n" 0 2 (:parent #430))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #420))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #421) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #424)) #("\n" 0 1 (:parent #424))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #421) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #425)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #425)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #425)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #425)) #("file.\n" 0 6 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #421)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #421)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #421) #(" If the package is not available, this would return a " 0 55 (:parent #428)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #428)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #428)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #428)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #428)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #428)) #("below.\n" 0 7 (:parent #428))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #421) #(" #+begin" 0 9 (:parent #429)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #429) #("src" 0 3 (:parent #433))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #429)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #429) #("nar" 0 3 (:parent #435))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #429)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #429) #("pass" 0 4 (:parent #437))) #("\" url \";\")\n \"client" 0 25 (:parent #429)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #429) #("body" 0 4 (:parent #439))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #429) #("buffer" 0 6 (:parent #440))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #429) #("size" 0 4 (:parent #441))) #("256k;\"\n" 0 7 (:parent #429)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #350) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #353) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #356) #("Guix channels" 0 13 (:parent #360))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #356)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #354) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #357) #("In order to run Cuirass via the " 0 32 (:parent #360)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #360)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #360)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #360)) #("as a " 0 5 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #360) #("G-Expression" 0 12 (:parent #368))) #("that will return a list of\n" 0 27 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #360) #("cuirass specifications" 0 22 (:parent #370))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #357)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #357) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #362)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #362)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #362)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #362) #("Cuirass specification" 0 21 (:parent #368))) #("\ndocumentation for more details.\n" 0 33 (:parent #362))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #357) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #363)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #363) #("Guix Configuration as a Channel" 0 31 (:parent #367))) #(".\n" 0 2 (:parent #363))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #355) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #358) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #361)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #361)) #("field of our " 0 13 (:parent #361)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #361)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #358))))) ((other "Cuirass" "-" "Building" "Packages") . 30823953) ((headline "Cuirass" "-" "Building" "Packages") . 30823953) ("org46b8c57" headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #353))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #399) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #402)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #402)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #402) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #415))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #402) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #416))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #402) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #417))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #402) #("Earlier this year " 0 18 (:parent #418)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #418) #("I announced on the guix mailing list" 0 36 (:parent #422))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #418)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #403))) :mode nil :granularity nil :parent #399) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #403) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #406) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #409))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #406) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #413) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #416) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #419) #("Improved Build Diversity" 0 24 (:parent #422)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #416)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #414) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #417) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #420) #("Reduced Latency" 0 15 (:parent #423)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #417)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #415) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #418) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #421) #("Increased Resilience" 0 20 (:parent #424)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #418)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #416) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #419) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #422) #("Community Contribution" 0 22 (:parent #425)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #419))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #406) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #411)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #411) #("here" 0 4 (:parent #415))) #(".\n" 0 2 (:parent #411))))) #353 (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #405))) :mode nil :granularity nil :parent #399) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #408))) :mode section :granularity nil :parent #405) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #408) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #411) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #414)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #414) #("Guix channels" 0 13 (:parent #418))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #414)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #412) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #415) #("In order to run Cuirass via the " 0 32 (:parent #418)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #418)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #418)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #418)) #("as a " 0 5 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #418) #("G-Expression" 0 12 (:parent #426))) #("that will return a list of\n" 0 27 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #418) #("cuirass specifications" 0 22 (:parent #428))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #415)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #415) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #420)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #420)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #420) #("Cuirass specification" 0 21 (:parent #426))) #("\ndocumentation for more details.\n" 0 33 (:parent #420))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #415) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #421)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #421) #("Guix Configuration as a Channel" 0 31 (:parent #425))) #(".\n" 0 2 (:parent #421))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #413) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #416) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #419)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #419)) #("field of our " 0 13 (:parent #419)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #419)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #416))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #409))) :mode nil :granularity nil :parent #405) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #409) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #412) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #415)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #415) #("guix publish" 0 12 (:parent #419))) #(", which Guix provides the " 0 26 (:parent #415)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #415) #("guix-publish-service-type" 0 25 (:parent #421))) #(",\nwhich is used in the " 0 23 (:parent #415)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #415)) #("field of " 0 9 (:parent #415)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #415)) #("definition.\n" 0 12 (:parent #415))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #412)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #412) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #417))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #410))) :mode nil :granularity nil :parent #405) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #410) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #413) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #416))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #413) #("To anonymize nginx access logs, the " 0 36 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #417) #("anonip-service-type" 0 19 (:parent #421))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #417)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #417)) #("is defined.\n" 0 12 (:parent #417))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #413) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #413) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #421)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #421)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #413)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #413) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #423)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #423)) #("field of our\n" 0 13 (:parent #423)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #423)) #("declaration.\n" 0 13 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #413)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #411))) :mode nil :granularity nil :parent #405) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #411) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #414) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #417)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #415) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #418) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #421)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #421) #("letsencrypt" 0 11 (:parent #425))) #("via the " 0 8 (:parent #421)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #421) #("certbot" 0 7 (:parent #427))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #421) #("certbox-service-type" 0 20 (:parent #429))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #421)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #421)) #("field in our " 0 13 (:parent #421)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #421)) #("configuration.\n" 0 15 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #418) #("This service references " 0 24 (:parent #423)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #423)) #(", which we define below. It sends " 0 34 (:parent #423)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #423)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #418) #("Next we define a function we will use later in the " 0 51 (:parent #425)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #425) #("Configure Nginx Server Blocks" 0 29 (:parent #429))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #418)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #416)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #416) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #419) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #419)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #419) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #424))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #419) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #428) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #431)) #("\n" 0 1 (:parent #431))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #428) #(" " 0 2 (:parent #432)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #432)) #("provides a route " 0 17 (:parent #432)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #432)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #432)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #432)) #("command). Given away by the reference to " 0 41 (:parent #432)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #432) #("Nix" 0 3 (:parent #442))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #432)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #432) #("Nix Binary Cache" 0 16 (:parent #444))) #(".\n" 0 2 (:parent #432))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #428) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #433))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #428)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #428) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #435))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #428))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #429) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #432)) #("\n" 0 1 (:parent #432))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #429) #(" " 0 2 (:parent #433)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #433) #("NAR (Nix Archive Format)" 0 24 (:parent #437))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #433)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #433) #("hello" 0 5 (:parent #439))) #("package.\n" 0 9 (:parent #433))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #429) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #429)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #429)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #429) #(" The result is composed of a few parts:\n" 0 41 (:parent #437))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #429) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #441))) :mode item :granularity nil :parent #438) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #441) #("the guix store path\n" 0 20 (:parent #444)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #442))) :mode item :granularity nil :parent #438) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #442) #("a hash uniquely identifying the store item\n" 0 43 (:parent #445)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #443))) :mode item :granularity nil :parent #438) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #443) #("the package-name and version, separated by dashes\n" 0 50 (:parent #446))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #429) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #439)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #439)) #(".\n" 0 2 (:parent #439))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #429))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #430) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #433)) #("\n" 0 1 (:parent #433))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #430) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #434)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #434)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #434)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #434)) #("file.\n" 0 6 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #430)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #430)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #430) #(" If the package is not available, this would return a " 0 55 (:parent #437)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #437)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #437)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #437)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #437)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #437)) #("below.\n" 0 7 (:parent #437))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #430) #(" #+begin" 0 9 (:parent #438)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #438) #("src" 0 3 (:parent #442))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #438)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #438) #("nar" 0 3 (:parent #444))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #438)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #438) #("pass" 0 4 (:parent #446))) #("\" url \";\")\n \"client" 0 25 (:parent #438)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #438) #("body" 0 4 (:parent #448))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #438) #("buffer" 0 6 (:parent #449))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #438) #("size" 0 4 (:parent #450))) #("256k;\"\n" 0 7 (:parent #438))))))))))) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #353) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #356) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #359))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #356) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #363) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #366) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #369) #("Processor" 0 9 (:parent #372)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #366)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #364) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #367) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #370) #("RAM" 0 3 (:parent #373)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #367)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #365) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #368) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #371) #("Storage" 0 7 (:parent #374)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #368)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #366) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #369) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #372) #("Network" 0 7 (:parent #375)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #369)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #367) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #370) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #373) #("Location" 0 8 (:parent #376)))) #(": Memphis TN\n" 0 13 (:parent #370))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #356) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #361))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #356) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #362))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #356) #("For more details, see the " 0 26 (:parent #363)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #363) #("Specifications section" 0 22 (:parent #367))) #("of the Cuirass Manual.\n" 0 23 (:parent #363))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #356) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #364))))) ((other "Hardware" "and" "Infrastructure") . 74157143) ((headline "Hardware" "and" "Infrastructure") . 74157143) ("orgcc40a3d" headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #356))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #402) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #405)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #405)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #405) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #418))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #405) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #419))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #405) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #420))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #405) #("Earlier this year " 0 18 (:parent #421)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #421) #("I announced on the guix mailing list" 0 36 (:parent #425))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #421)))) #356 (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #407) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #410) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #413))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #417) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #420) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #423) #("Processor" 0 9 (:parent #426)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #420)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #418) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #421) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #424) #("RAM" 0 3 (:parent #427)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #421)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #419) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #422) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #425) #("Storage" 0 7 (:parent #428)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #422)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #420) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #423) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #426) #("Network" 0 7 (:parent #429)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #423)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #421) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #424) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #427) #("Location" 0 8 (:parent #430)))) #(": Memphis TN\n" 0 13 (:parent #424))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #410) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #415))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #410) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #416))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #410) #("For more details, see the " 0 26 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #417) #("Specifications section" 0 22 (:parent #421))) #("of the Cuirass Manual.\n" 0 23 (:parent #417))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #410) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #418))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #408))) :mode nil :granularity nil :parent #402) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #411))) :mode section :granularity nil :parent #408) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #411) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #414) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #417) #("Guix channels" 0 13 (:parent #421))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #417)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #415) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #418) #("In order to run Cuirass via the " 0 32 (:parent #421)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #421)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #421)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #421)) #("as a " 0 5 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #421) #("G-Expression" 0 12 (:parent #429))) #("that will return a list of\n" 0 27 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #421) #("cuirass specifications" 0 22 (:parent #431))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #418)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #418) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #423)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #423)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #423)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #423) #("Cuirass specification" 0 21 (:parent #429))) #("\ndocumentation for more details.\n" 0 33 (:parent #423))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #418) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #424)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #424) #("Guix Configuration as a Channel" 0 31 (:parent #428))) #(".\n" 0 2 (:parent #424))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #416) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #419) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #422)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #422)) #("field of our " 0 13 (:parent #422)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #422)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #419))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #412) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #415) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #418) #("guix publish" 0 12 (:parent #422))) #(", which Guix provides the " 0 26 (:parent #418)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #418) #("guix-publish-service-type" 0 25 (:parent #424))) #(",\nwhich is used in the " 0 23 (:parent #418)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #418)) #("field of " 0 9 (:parent #418)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #418)) #("definition.\n" 0 12 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #415)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #415) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #420))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #413) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #416) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #419))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #416) #("To anonymize nginx access logs, the " 0 36 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #420) #("anonip-service-type" 0 19 (:parent #424))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #420)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #420)) #("is defined.\n" 0 12 (:parent #420))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #416) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #416) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #424)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #424)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #416)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #416) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #426)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #426)) #("field of our\n" 0 13 (:parent #426)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #426)) #("declaration.\n" 0 13 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #416)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #414))) :mode nil :granularity nil :parent #408) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #414) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #417) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #420)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #418))) :mode nil :granularity nil :parent #414) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #418) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #421) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #424)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #424) #("letsencrypt" 0 11 (:parent #428))) #("via the " 0 8 (:parent #424)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #424) #("certbot" 0 7 (:parent #430))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #424)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #424) #("certbox-service-type" 0 20 (:parent #432))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #424)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #424)) #("field in our " 0 13 (:parent #424)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #424)) #("configuration.\n" 0 15 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #421) #("This service references " 0 24 (:parent #426)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #426)) #(", which we define below. It sends " 0 34 (:parent #426)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #426)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #421) #("Next we define a function we will use later in the " 0 51 (:parent #428)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #428) #("Configure Nginx Server Blocks" 0 29 (:parent #432))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #428))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #421)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #419)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #419))) :mode nil :granularity nil :parent #414) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #419) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #422) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #422)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #422) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #427))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #422) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #431) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #434)) #("\n" 0 1 (:parent #434))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #431) #(" " 0 2 (:parent #435)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #435)) #("provides a route " 0 17 (:parent #435)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #435)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #435)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #435)) #("command). Given away by the reference to " 0 41 (:parent #435)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #435) #("Nix" 0 3 (:parent #445))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #435)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #435) #("Nix Binary Cache" 0 16 (:parent #447))) #(".\n" 0 2 (:parent #435))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #431) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #436))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #431)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #431) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #438))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #431))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #432) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #435)) #("\n" 0 1 (:parent #435))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #432) #(" " 0 2 (:parent #436)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #436) #("NAR (Nix Archive Format)" 0 24 (:parent #440))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #436)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #436) #("hello" 0 5 (:parent #442))) #("package.\n" 0 9 (:parent #436))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #432) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #432)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #432)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #432) #(" The result is composed of a few parts:\n" 0 41 (:parent #440))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #432) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #444))) :mode item :granularity nil :parent #441) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #444) #("the guix store path\n" 0 20 (:parent #447)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #445))) :mode item :granularity nil :parent #441) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #445) #("a hash uniquely identifying the store item\n" 0 43 (:parent #448)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #446))) :mode item :granularity nil :parent #441) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #446) #("the package-name and version, separated by dashes\n" 0 50 (:parent #449))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #432) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #442)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #442)) #(".\n" 0 2 (:parent #442))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #432))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #433) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #436)) #("\n" 0 1 (:parent #436))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #433) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #437)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #437)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #437)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #437)) #("file.\n" 0 6 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #433)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #433)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #433) #(" If the package is not available, this would return a " 0 55 (:parent #440)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #440)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #440)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #440)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #440)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #440)) #("below.\n" 0 7 (:parent #440))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #433) #(" #+begin" 0 9 (:parent #441)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #441) #("src" 0 3 (:parent #445))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #441)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #441) #("nar" 0 3 (:parent #447))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #441)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #441) #("pass" 0 4 (:parent #449))) #("\" url \";\")\n \"client" 0 25 (:parent #441)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #441) #("body" 0 4 (:parent #451))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #441) #("buffer" 0 6 (:parent #452))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #441) #("size" 0 4 (:parent #453))) #("256k;\"\n" 0 7 (:parent #441))))))))))) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #356) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #359) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #362))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #359) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #366) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #369) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #372) #("Improved Build Diversity" 0 24 (:parent #375)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #369)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #367) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #370) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #373) #("Reduced Latency" 0 15 (:parent #376)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #370)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #368) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #371) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #374) #("Increased Resilience" 0 20 (:parent #377)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #371)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #369) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #372) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #375) #("Community Contribution" 0 22 (:parent #378)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #372))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #359) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #364)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #364) #("here" 0 4 (:parent #368))) #(".\n" 0 2 (:parent #364))))) ((other "Why" "Build" "Another" "Substitute" "Server?") . 214174269) ((headline "Why" "Build" "Another" "Substitute" "Server?") . 214174269)) :resolve-fuzzy-link-cache #))
#f(compiled-function (element) #)((section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #24))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #70))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #116))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #162) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #165)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #165)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #165)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #165) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #178))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #165) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #179))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #165) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #180))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #165) #("Earlier this year " 0 18 (:parent #181)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #181) #("I announced on the guix mailing list" 0 36 (:parent #185))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #181)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #166))) :mode nil :granularity nil :parent #162) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #166) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #169) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #172))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #169) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #173) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #176) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #179) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #182) #("Improved Build Diversity" 0 24 (:parent #185)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #179)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #173) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #177) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #180) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #183) #("Reduced Latency" 0 15 (:parent #186)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #180)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #173) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #178) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #181) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #184) #("Increased Resilience" 0 20 (:parent #187)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #181)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #173) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #179) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #182) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #185) #("Community Contribution" 0 22 (:parent #188)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #182))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #169) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #174)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #174) #("here" 0 4 (:parent #178))) #(".\n" 0 2 (:parent #174))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #167))) :mode nil :granularity nil :parent #162) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #167) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #170) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #173))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #170) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #177) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #180) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #183) #("Processor" 0 9 (:parent #186)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #180)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #178) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #181) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #184) #("RAM" 0 3 (:parent #187)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #181)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #179) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #182) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #185) #("Storage" 0 7 (:parent #188)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #182)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #180) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #183) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #186) #("Network" 0 7 (:parent #189)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #183)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #181) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #184) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #187) #("Location" 0 8 (:parent #190)))) #(": Memphis TN\n" 0 13 (:parent #184))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #170) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #175))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #170) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #176))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #170) #("For more details, see the " 0 26 (:parent #177)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #177) #("Specifications section" 0 22 (:parent #181))) #("of the Cuirass Manual.\n" 0 23 (:parent #177))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #170) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #178))))) #116)) #70 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #120))) :mode nil :granularity nil :parent #116) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #120) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #123) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #126)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #126) #("guix publish" 0 12 (:parent #130))) #(", which Guix provides the " 0 26 (:parent #126)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #126) #("guix-publish-service-type" 0 25 (:parent #132))) #(",\nwhich is used in the " 0 23 (:parent #126)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #126)) #("field of " 0 9 (:parent #126)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #126)) #("definition.\n" 0 12 (:parent #126))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #123)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #123) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #128))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #121))) :mode nil :granularity nil :parent #116) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #121) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #124) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #127))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #124) #("To anonymize nginx access logs, the " 0 36 (:parent #128)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #128) #("anonip-service-type" 0 19 (:parent #132))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #128)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #128)) #("is defined.\n" 0 12 (:parent #128))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #124)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #124) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #130))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #124)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #124) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #132)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #132)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #132))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #124)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #124) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #134)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #134)) #("field of our\n" 0 13 (:parent #134)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #134)) #("declaration.\n" 0 13 (:parent #134))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #124)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #122))) :mode nil :granularity nil :parent #116) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #122) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #125) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #128)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #126))) :mode nil :granularity nil :parent #122) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #126) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #129) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #132)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #132) #("letsencrypt" 0 11 (:parent #136))) #("via the " 0 8 (:parent #132)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #132) #("certbot" 0 7 (:parent #138))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #132)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #132) #("certbox-service-type" 0 20 (:parent #140))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #132)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #132)) #("field in our " 0 13 (:parent #132)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #132)) #("configuration.\n" 0 15 (:parent #132))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #129)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #129) #("This service references " 0 24 (:parent #134)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #134)) #(", which we define below. It sends " 0 34 (:parent #134)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #134)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #134))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #129)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #129) #("Next we define a function we will use later in the " 0 51 (:parent #136)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #136) #("Configure Nginx Server Blocks" 0 29 (:parent #140))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #136))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #129)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #127)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #127))) :mode nil :granularity nil :parent #122) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #127) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #130) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #133))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #130)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #130) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #135))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #130) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #136) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #139) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #142)) #("\n" 0 1 (:parent #142))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #139) #(" " 0 2 (:parent #143)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #143)) #("provides a route " 0 17 (:parent #143)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #143)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #143)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #143)) #("command). Given away by the reference to " 0 41 (:parent #143)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #143) #("Nix" 0 3 (:parent #153))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #143)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #143) #("Nix Binary Cache" 0 16 (:parent #155))) #(".\n" 0 2 (:parent #143))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #139) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #144))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #139)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #139) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #146))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #139))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #136) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #140) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #143)) #("\n" 0 1 (:parent #143))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #140) #(" " 0 2 (:parent #144)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #144) #("NAR (Nix Archive Format)" 0 24 (:parent #148))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #144)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #144) #("hello" 0 5 (:parent #150))) #("package.\n" 0 9 (:parent #144))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #140) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #145))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #140)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #140)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #140) #(" The result is composed of a few parts:\n" 0 41 (:parent #148))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #140) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #152))) :mode item :granularity nil :parent #149) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #152) #("the guix store path\n" 0 20 (:parent #155)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #153))) :mode item :granularity nil :parent #149) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #153) #("a hash uniquely identifying the store item\n" 0 43 (:parent #156)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #154))) :mode item :granularity nil :parent #149) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #154) #("the package-name and version, separated by dashes\n" 0 50 (:parent #157))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #140) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #150)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #150)) #(".\n" 0 2 (:parent #150))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #140))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #136) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #141) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #144)) #("\n" 0 1 (:parent #144))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #141) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #145)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #145)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #145)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #145)) #("file.\n" 0 6 (:parent #145))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #141)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #141)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #141) #(" If the package is not available, this would return a " 0 55 (:parent #148)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #148)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #148)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #148)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #148)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #148)) #("below.\n" 0 7 (:parent #148))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #141) #(" #+begin" 0 9 (:parent #149)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #149) #("src" 0 3 (:parent #153))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #149)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #149) #("nar" 0 3 (:parent #155))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #149)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #149) #("pass" 0 4 (:parent #157))) #("\" url \";\")\n \"client" 0 25 (:parent #149)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #149) #("body" 0 4 (:parent #159))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #149) #("buffer" 0 6 (:parent #160))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #149) #("size" 0 4 (:parent #161))) #("256k;\"\n" 0 7 (:parent #149)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #70) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #73) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #76)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #76) #("Guix channels" 0 13 (:parent #80))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #76)))) #24 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #75))) :mode nil :granularity nil :parent #70) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #75) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #78) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #81)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #81)) #("field of our " 0 13 (:parent #81)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #81)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #81))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #78)))))) #0)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #0) #("In order to run Cuirass via the " 0 32 (:parent #3)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #3)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #3)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #3)) #("as a " 0 5 (:parent #3)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #3) #("G-Expression" 0 12 (:parent #11))) #("that will return a list of\n" 0 27 (:parent #3)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #3) #("cuirass specifications" 0 22 (:parent #13))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #3))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #0)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #0) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #5)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #5)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #5)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #5) #("Cuirass specification" 0 21 (:parent #11))) #("\ndocumentation for more details.\n" 0 33 (:parent #5))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #0) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #6)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #6) #("Guix Configuration as a Channel" 0 31 (:parent #10))) #(".\n" 0 2 (:parent #6)))))
mapconcat(#f(compiled-function (element) #) ((section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #25))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #71))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #117))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #163) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #166)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #166)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #166)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #166)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #166)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #166)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #166)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #166)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #166)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #166)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #166) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #179))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #166) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #180))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #166) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #181))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #166) #("Earlier this year " 0 18 (:parent #182)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #182) #("I announced on the guix mailing list" 0 36 (:parent #186))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #182)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #167))) :mode nil :granularity nil :parent #163) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #167) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #170) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #173))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #170) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #177) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #180) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #183) #("Improved Build Diversity" 0 24 (:parent #186)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #180)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #178) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #181) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #184) #("Reduced Latency" 0 15 (:parent #187)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #181)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #179) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #182) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #185) #("Increased Resilience" 0 20 (:parent #188)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #182)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #174) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #180) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #183) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #186) #("Community Contribution" 0 22 (:parent #189)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #183))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #170) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #175)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #175) #("here" 0 4 (:parent #179))) #(".\n" 0 2 (:parent #175))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #168))) :mode nil :granularity nil :parent #163) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #168) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #171) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #174))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #171) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #175) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #178) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #181) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #184) #("Processor" 0 9 (:parent #187)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #181)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #175) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #179) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #182) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #185) #("RAM" 0 3 (:parent #188)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #182)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #175) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #180) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #183) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #186) #("Storage" 0 7 (:parent #189)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #183)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #175) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #181) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #184) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #187) #("Network" 0 7 (:parent #190)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #184)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #175) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #182) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #185) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #188) #("Location" 0 8 (:parent #191)))) #(": Memphis TN\n" 0 13 (:parent #185))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #171) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #176))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #171) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #177))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #171) #("For more details, see the " 0 26 (:parent #178)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #178) #("Specifications section" 0 22 (:parent #182))) #("of the Cuirass Manual.\n" 0 23 (:parent #178))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #171) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #179))))) #117)) #71 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #121))) :mode nil :granularity nil :parent #117) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #121) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #124) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #127)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #127) #("guix publish" 0 12 (:parent #131))) #(", which Guix provides the " 0 26 (:parent #127)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #127) #("guix-publish-service-type" 0 25 (:parent #133))) #(",\nwhich is used in the " 0 23 (:parent #127)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #127)) #("field of " 0 9 (:parent #127)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #127)) #("definition.\n" 0 12 (:parent #127))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #124)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #124) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #129))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #122))) :mode nil :granularity nil :parent #117) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #122) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #125) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #128))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #125) #("To anonymize nginx access logs, the " 0 36 (:parent #129)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #129) #("anonip-service-type" 0 19 (:parent #133))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #129)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #129)) #("is defined.\n" 0 12 (:parent #129))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #125)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #125) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #131))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #125)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #125) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #133)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #133)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #133))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #125)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #125) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #135)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #135)) #("field of our\n" 0 13 (:parent #135)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #135)) #("declaration.\n" 0 13 (:parent #135))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #125)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #123))) :mode nil :granularity nil :parent #117) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #123) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #126) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #129)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #127))) :mode nil :granularity nil :parent #123) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #127) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #130) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #133)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #133) #("letsencrypt" 0 11 (:parent #137))) #("via the " 0 8 (:parent #133)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #133) #("certbot" 0 7 (:parent #139))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #133)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #133) #("certbox-service-type" 0 20 (:parent #141))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #133)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #133)) #("field in our " 0 13 (:parent #133)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #133)) #("configuration.\n" 0 15 (:parent #133))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #130)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #130) #("This service references " 0 24 (:parent #135)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #135)) #(", which we define below. It sends " 0 34 (:parent #135)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #135)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #135))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #130)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #130) #("Next we define a function we will use later in the " 0 51 (:parent #137)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #137) #("Configure Nginx Server Blocks" 0 29 (:parent #141))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #137))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #130)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #128)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #128))) :mode nil :granularity nil :parent #123) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #128) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #131) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #134))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #131)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #131) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #136))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #131) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #137) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #140) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #143)) #("\n" 0 1 (:parent #143))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #140) #(" " 0 2 (:parent #144)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #144)) #("provides a route " 0 17 (:parent #144)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #144)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #144)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #144)) #("command). Given away by the reference to " 0 41 (:parent #144)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #144) #("Nix" 0 3 (:parent #154))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #144)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #144) #("Nix Binary Cache" 0 16 (:parent #156))) #(".\n" 0 2 (:parent #144))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #140) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #145))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #140)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #140) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #147))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #140))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #137) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #141) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #144)) #("\n" 0 1 (:parent #144))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #141) #(" " 0 2 (:parent #145)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #145) #("NAR (Nix Archive Format)" 0 24 (:parent #149))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #145)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #145) #("hello" 0 5 (:parent #151))) #("package.\n" 0 9 (:parent #145))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #141) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #146))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #141)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #141)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #141) #(" The result is composed of a few parts:\n" 0 41 (:parent #149))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #141) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #153))) :mode item :granularity nil :parent #150) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #153) #("the guix store path\n" 0 20 (:parent #156)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #154))) :mode item :granularity nil :parent #150) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #154) #("a hash uniquely identifying the store item\n" 0 43 (:parent #157)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #155))) :mode item :granularity nil :parent #150) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #155) #("the package-name and version, separated by dashes\n" 0 50 (:parent #158))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #141) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #151)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #151)) #(".\n" 0 2 (:parent #151))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #141))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #137) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #142) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #145)) #("\n" 0 1 (:parent #145))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #142) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #146)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #146)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #146)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #146)) #("file.\n" 0 6 (:parent #146))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #142)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #142)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #142) #(" If the package is not available, this would return a " 0 55 (:parent #149)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #149)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #149)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #149)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #149)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #149)) #("below.\n" 0 7 (:parent #149))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #142) #(" #+begin" 0 9 (:parent #150)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #150) #("src" 0 3 (:parent #154))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #150)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #150) #("nar" 0 3 (:parent #156))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #150)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #150) #("pass" 0 4 (:parent #158))) #("\" url \";\")\n \"client" 0 25 (:parent #150)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #150) #("body" 0 4 (:parent #160))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #150) #("buffer" 0 6 (:parent #161))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #150) #("size" 0 4 (:parent #162))) #("256k;\"\n" 0 7 (:parent #150)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #71) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #74) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #77)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #77) #("Guix channels" 0 13 (:parent #81))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #77)))) #25 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #76))) :mode nil :granularity nil :parent #71) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #76) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #79) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #82)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #82)) #("field of our " 0 13 (:parent #82)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #82)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #82))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #79)))))) . #0)) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #1) #("In order to run Cuirass via the " 0 32 (:parent #4)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #4)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #4)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #4)) #("as a " 0 5 (:parent #4)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #4) #("G-Expression" 0 12 (:parent #12))) #("that will return a list of\n" 0 27 (:parent #4)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #4) #("cuirass specifications" 0 22 (:parent #14))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #4))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #1)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #1) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #6)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #6)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #6)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #6) #("Cuirass specification" 0 21 (:parent #12))) #("\ndocumentation for more details.\n" 0 33 (:parent #6))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #1) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #7)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #7) #("Guix Configuration as a Channel" 0 31 (:parent #11))) #(".\n" 0 2 (:parent #7))))) "")
org-export-data((headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #0))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #46))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #92))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #138) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #141)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #141)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #141) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #154))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #141) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #155))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #141) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #156))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #141) #("Earlier this year " 0 18 (:parent #157)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #157) #("I announced on the guix mailing list" 0 36 (:parent #161))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #157)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #142))) :mode nil :granularity nil :parent #138) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #142) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #145) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #148))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #145) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #149) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #152) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #155) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #158) #("Improved Build Diversity" 0 24 (:parent #161)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #155)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #149) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #153) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #156) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #159) #("Reduced Latency" 0 15 (:parent #162)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #156)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #149) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #154) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #157) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #160) #("Increased Resilience" 0 20 (:parent #163)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #157)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #149) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #155) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #158) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #161) #("Community Contribution" 0 22 (:parent #164)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #158))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #145) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #150)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #150) #("here" 0 4 (:parent #154))) #(".\n" 0 2 (:parent #150))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #143))) :mode nil :granularity nil :parent #138) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #143) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #146) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #149))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #146) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #153) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #156) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #159) #("Processor" 0 9 (:parent #162)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #156)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #154) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #157) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #160) #("RAM" 0 3 (:parent #163)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #157)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #155) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #158) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #161) #("Storage" 0 7 (:parent #164)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #158)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #156) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #159) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #162) #("Network" 0 7 (:parent #165)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #159)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #157) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #160) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #163) #("Location" 0 8 (:parent #166)))) #(": Memphis TN\n" 0 13 (:parent #160))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #146) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #151))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #146) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #152))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #146) #("For more details, see the " 0 26 (:parent #153)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #153) #("Specifications section" 0 22 (:parent #157))) #("of the Cuirass Manual.\n" 0 23 (:parent #153))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #146) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #154))))) #92)) #46 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #96))) :mode nil :granularity nil :parent #92) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #96) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #99) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #102)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #102) #("guix publish" 0 12 (:parent #106))) #(", which Guix provides the " 0 26 (:parent #102)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #102) #("guix-publish-service-type" 0 25 (:parent #108))) #(",\nwhich is used in the " 0 23 (:parent #102)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #102)) #("field of " 0 9 (:parent #102)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #102)) #("definition.\n" 0 12 (:parent #102))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #99)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #99) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #104))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #97))) :mode nil :granularity nil :parent #92) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #97) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #100) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #103))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #100) #("To anonymize nginx access logs, the " 0 36 (:parent #104)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #104) #("anonip-service-type" 0 19 (:parent #108))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #104)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #104)) #("is defined.\n" 0 12 (:parent #104))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #100)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #100) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #106))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #100)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #100) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #108)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #108)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #108))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #100)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #100) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #110)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #110)) #("field of our\n" 0 13 (:parent #110)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #110)) #("declaration.\n" 0 13 (:parent #110))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #100)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #98))) :mode nil :granularity nil :parent #92) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #98) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #101) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #104)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #102))) :mode nil :granularity nil :parent #98) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #102) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #105) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #108)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #108) #("letsencrypt" 0 11 (:parent #112))) #("via the " 0 8 (:parent #108)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #108) #("certbot" 0 7 (:parent #114))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #108)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #108) #("certbox-service-type" 0 20 (:parent #116))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #108)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #108)) #("field in our " 0 13 (:parent #108)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #108)) #("configuration.\n" 0 15 (:parent #108))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #105)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #105) #("This service references " 0 24 (:parent #110)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #110)) #(", which we define below. It sends " 0 34 (:parent #110)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #110)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #110))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #105)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #105) #("Next we define a function we will use later in the " 0 51 (:parent #112)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #112) #("Configure Nginx Server Blocks" 0 29 (:parent #116))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #112))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #105)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #103)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #103))) :mode nil :granularity nil :parent #98) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #103) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #106) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #109))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #106)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #106) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #111))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #106) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #112) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #115) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #118)) #("\n" 0 1 (:parent #118))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #115) #(" " 0 2 (:parent #119)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #119)) #("provides a route " 0 17 (:parent #119)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #119)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #119)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #119)) #("command). Given away by the reference to " 0 41 (:parent #119)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #119) #("Nix" 0 3 (:parent #129))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #119)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #119) #("Nix Binary Cache" 0 16 (:parent #131))) #(".\n" 0 2 (:parent #119))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #115) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #120))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #115)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #115) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #122))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #115))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #112) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #116) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #119)) #("\n" 0 1 (:parent #119))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #116) #(" " 0 2 (:parent #120)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #120) #("NAR (Nix Archive Format)" 0 24 (:parent #124))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #120)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #120) #("hello" 0 5 (:parent #126))) #("package.\n" 0 9 (:parent #120))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #116) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #121))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #116)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #116)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #116) #(" The result is composed of a few parts:\n" 0 41 (:parent #124))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #116) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #128))) :mode item :granularity nil :parent #125) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #128) #("the guix store path\n" 0 20 (:parent #131)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #129))) :mode item :granularity nil :parent #125) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #129) #("a hash uniquely identifying the store item\n" 0 43 (:parent #132)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #130))) :mode item :granularity nil :parent #125) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #130) #("the package-name and version, separated by dashes\n" 0 50 (:parent #133))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #116) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #126)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #126)) #(".\n" 0 2 (:parent #126))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #116))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #112) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #117) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #120)) #("\n" 0 1 (:parent #120))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #117) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #121)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #121)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #121)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #121)) #("file.\n" 0 6 (:parent #121))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #117)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #117)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #117) #(" If the package is not available, this would return a " 0 55 (:parent #124)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #124)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #124)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #124)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #124)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #124)) #("below.\n" 0 7 (:parent #124))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #117) #(" #+begin" 0 9 (:parent #125)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #125) #("src" 0 3 (:parent #129))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #125)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #125) #("nar" 0 3 (:parent #131))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #125)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #125) #("pass" 0 4 (:parent #133))) #("\" url \";\")\n \"client" 0 25 (:parent #125)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #125) #("body" 0 4 (:parent #135))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #125) #("buffer" 0 6 (:parent #136))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #125) #("size" 0 4 (:parent #137))) #("256k;\"\n" 0 7 (:parent #125)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #46) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #49) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #52)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #52) #("Guix channels" 0 13 (:parent #56))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #52)))) #0 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #51))) :mode nil :granularity nil :parent #46) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #51) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #54) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #57)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #57)) #("field of our " 0 13 (:parent #57)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #57)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #57))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #54)))))) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #0) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #3) #("In order to run Cuirass via the " 0 32 (:parent #6)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #6)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #6)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #6)) #("as a " 0 5 (:parent #6)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #6) #("G-Expression" 0 12 (:parent #14))) #("that will return a list of\n" 0 27 (:parent #6)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #6) #("cuirass specifications" 0 22 (:parent #16))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #6))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #3)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #3) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #8)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #8)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #8)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #8) #("Cuirass specification" 0 21 (:parent #14))) #("\ndocumentation for more details.\n" 0 33 (:parent #8))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #3) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #9)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #9) #("Guix Configuration as a Channel" 0 31 (:parent #13))) #(".\n" 0 2 (:parent #9))))) (:export-options (body-only) :back-end #s(org-export-backend :name html :parent nil :transcoders ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :options ((:html-doctype "HTML_DOCTYPE" nil org-html-doctype) (:html-container "HTML_CONTAINER" nil org-html-container-element) (:html-content-class "HTML_CONTENT_CLASS" nil org-html-content-class) (:description "DESCRIPTION" nil nil newline) (:keywords "KEYWORDS" nil nil space) (:html-html5-fancy nil "html5-fancy" org-html-html5-fancy) (:html-link-use-abs-url nil "html-link-use-abs-url" org-html-link-use-abs-url) (:html-link-home "HTML_LINK_HOME" nil org-html-link-home) (:html-link-up "HTML_LINK_UP" nil org-html-link-up) (:html-mathjax "HTML_MATHJAX" nil "" space) (:html-equation-reference-format "HTML_EQUATION_REFERENCE_FORMAT" nil org-html-equation-reference-format t) (:html-postamble nil "html-postamble" org-html-postamble) (:html-preamble nil "html-preamble" org-html-preamble) (:html-head "HTML_HEAD" nil org-html-head newline) (:html-head-extra "HTML_HEAD_EXTRA" nil org-html-head-extra newline) (:subtitle "SUBTITLE" nil nil parse) (:html-head-include-default-style nil "html-style" org-html-head-include-default-style) (:html-head-include-scripts nil "html-scripts" org-html-head-include-scripts) (:html-allow-name-attribute-in-anchors nil nil org-html-allow-name-attribute-in-anchors) (:html-divs nil nil org-html-divs) (:html-checkbox-type nil nil org-html-checkbox-type) (:html-extension nil nil org-html-extension) (:html-footnote-format nil nil org-html-footnote-format) (:html-footnote-separator nil nil org-html-footnote-separator) (:html-footnotes-section nil nil org-html-footnotes-section) (:html-format-drawer-function nil nil org-html-format-drawer-function) (:html-format-headline-function nil nil org-html-format-headline-function) (:html-format-inlinetask-function nil nil org-html-format-inlinetask-function) (:html-home/up-format nil nil org-html-home/up-format) (:html-indent nil nil org-html-indent) (:html-infojs-options nil nil org-html-infojs-options) (:html-infojs-template nil nil org-html-infojs-template) (:html-inline-image-rules nil nil org-html-inline-image-rules) (:html-link-org-files-as-html nil nil org-html-link-org-files-as-html) (:html-mathjax-options nil nil org-html-mathjax-options) (:html-mathjax-template nil nil org-html-mathjax-template) (:html-metadata-timestamp-format nil nil org-html-metadata-timestamp-format) (:html-postamble-format nil nil org-html-postamble-format) (:html-preamble-format nil nil org-html-preamble-format) (:html-prefer-user-labels nil nil org-html-prefer-user-labels) (:html-self-link-headlines nil nil org-html-self-link-headlines) (:html-table-align-individual-fields nil nil org-html-table-align-individual-fields) (:html-table-caption-above nil nil org-html-table-caption-above) (:html-table-data-tags nil nil org-html-table-data-tags) (:html-table-header-tags nil nil org-html-table-header-tags) (:html-table-use-header-tags-for-first-column nil nil org-html-table-use-header-tags-for-first-column) (:html-tag-class-prefix nil nil org-html-tag-class-prefix) (:html-text-markup-alist nil nil org-html-text-markup-alist) (:html-todo-kwd-class-prefix nil nil org-html-todo-kwd-class-prefix) (:html-toplevel-hlevel nil nil org-html-toplevel-hlevel) (:html-use-infojs nil nil org-html-use-infojs) (:html-validation-link nil nil org-html-validation-link) (:html-viewport nil nil org-html-viewport) (:html-inline-images nil nil org-html-inline-images) (:html-table-attributes nil nil org-html-table-default-attributes) (:html-table-row-open-tag nil nil org-html-table-row-open-tag) (:html-table-row-close-tag nil nil org-html-table-row-close-tag) (:html-xml-declaration nil nil org-html-xml-declaration) (:html-wrap-src-lines nil nil org-html-wrap-src-lines) (:html-klipsify-src nil nil org-html-klipsify-src) (:html-klipse-css nil nil org-html-klipse-css) (:html-klipse-js nil nil org-html-klipse-js) (:html-klipse-selection-script nil nil org-html-klipse-selection-script) (:infojs-opt "INFOJS_OPT" nil nil) (:creator "CREATOR" nil org-html-creator-string) (:with-latex nil "tex" org-html-with-latex) (:latex-header "LATEX_HEADER" nil nil newline)) :filters ((:filter-options . org-html-infojs-install-script) (:filter-parse-tree . org-html-image-link-filter) (:filter-final-output . org-html-final-function)) :blocks nil :menu (104 "Export to HTML" ((72 "As HTML buffer" org-html-export-as-html) (104 "As HTML file" org-html-export-to-html) (111 "As HTML file and open" (lambda (a s v b) (if a (org-html-export-to-html t s v b) (org-open-file (org-html-export-to-html nil s v b)))))))) :translate-alist ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data # :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil :html-divs ((preamble "div" "preamble") (content "div" "content") (postamble "div" "postamble")) :html-checkbox-type ascii :html-extension "html" :html-footnote-format "%s" :html-footnote-separator ", " :html-footnotes-section ") :html-format-headline-function org-html-format-headline-default-function :html-format-inlinetask-function org-html-format-inlinetask-default-function :html-home/up-format "" :html-indent nil :html-infojs-options ((path . "https://orgmode.org/org-info.js") (view . "info") (toc . :with-toc) (ftoc . "0") (tdepth . "max") (sdepth . "max") (mouse . "underline") (buttons . "0") (ltoc . "1") (up . :html-link-up) (home . :html-link-home)) :html-infojs-template "\n\n" :html-inline-image-rules (("file" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("http" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("https" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)")) :html-link-org-files-as-html t :html-mathjax-options ((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js") (scale 1.0) (align "center") (font "mathjax-modern") (overflow "overflow") (tags "ams") (indent "0em") (multlinewidth "85%") (tagindent ".8em") (tagside "right")) :html-mathjax-template "\n\n" :html-metadata-timestamp-format "%Y-%m-%d %a %H:%M" :html-postamble-format (("en" " \n" . " ") :html-table-header-tags ("" . " ") :html-table-use-header-tags-for-first-column nil :html-tag-class-prefix "" :html-text-markup-alist ((bold . "%s") (code . "%s") (underline . "%s") (verbatim . "" :html-table-row-close-tag " " :html-xml-declaration (("html" . "") ("php" . "\"; ?>")) :html-wrap-src-lines nil :html-klipsify-src nil :html-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css" :html-klipse-js "https://storage.googleapis.com/app.klipse.tech/plugin_prod/js/klipse_plugin.min.js" :html-klipse-selection-script "window.klipse_settings = {selector_eval_html: '.src-html',\n selector_eval_js: '.src-js',\n selector_eval_python_client: '.src-python',\n selector_eval_scheme: '.src-scheme',\n selector: '.src-clojure',\n selector_eval_ruby: '.src-ruby'};" :infojs-opt nil :creator "Emacs 29.4 (Org mode 9.6.15)" :with-latex t :latex-header "\\usepackage[margin=1.5cm]{geometry}\n\\usepackage{xcolor}\n\\definecolor{link}{HTML}{506060}\n\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :title (#("Setup of a Simple Guix Build Farm and Substitute Server" 0 55 (:parent #148))) :date nil :author (#("Collin J. Doering" 0 17 (:parent #152))) :email "unknown@genenetwork-development" :language "en" :select-tags ("export") :exclude-tags ("noexport") :headline-levels 3 :preserve-breaks nil :section-numbers nil :time-stamp-file t :with-archived-trees headline :with-author t :with-broken-links nil :with-clocks nil :with-creator nil :with-date t :with-drawers (not "LOGBOOK") :with-email nil :with-emphasize t :with-entities t :with-fixed-width t :with-footnotes t :with-inlinetasks t :with-planning nil :with-priority nil :with-properties nil :with-smart-quotes nil :with-special-strings t :with-statistics-cookies t :with-sub-superscript t :with-toc nil :with-tables t :with-tags t :with-tasks t :with-timestamps t :with-title t :with-todo-keywords t :cite-export (basic nil nil) :bibliography nil :filter-body nil :filter-bold nil :filter-babel-call nil :filter-center-block nil :filter-clock nil :filter-code nil :filter-diary-sexp nil :filter-drawer nil :filter-dynamic-block nil :filter-entity nil :filter-example-block nil :filter-export-block nil :filter-export-snippet nil :filter-final-output (org-html-final-function) :filter-fixed-width nil :filter-footnote-definition nil :filter-footnote-reference nil :filter-headline nil :filter-horizontal-rule nil :filter-inline-babel-call nil :filter-inline-src-block nil :filter-inlinetask nil :filter-italic nil :filter-item nil :filter-keyword nil :filter-latex-environment nil :filter-latex-fragment nil :filter-line-break nil :filter-link nil :filter-node-property nil :filter-options (org-html-infojs-install-script) :filter-paragraph nil :filter-parse-tree (org-html-image-link-filter) :filter-plain-list nil :filter-plain-text nil :filter-planning nil :filter-property-drawer nil :filter-quote-block nil :filter-radio-target nil :filter-section nil :filter-special-block nil :filter-src-block nil :filter-statistics-cookie nil :filter-strike-through nil :filter-subscript nil :filter-superscript nil :filter-table nil :filter-table-cell nil :filter-table-row nil :filter-target nil :filter-timestamp nil :filter-underline nil :filter-verbatim nil :filter-verse-block nil :ignore-list nil :parse-tree (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #338) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #341)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #341)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #341) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #354))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #341) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #355))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #341) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #356))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #341) #("Earlier this year " 0 18 (:parent #357)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #357) #("I announced on the guix mailing list" 0 36 (:parent #361))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #357)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #342))) :mode nil :granularity nil :parent #338) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #342) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #345) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #348))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #345) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #352) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #355) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #358) #("Improved Build Diversity" 0 24 (:parent #361)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #355)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #353) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #356) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #359) #("Reduced Latency" 0 15 (:parent #362)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #356)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #354) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #357) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #360) #("Increased Resilience" 0 20 (:parent #363)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #357)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #355) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #358) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #361) #("Community Contribution" 0 22 (:parent #364)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #358))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #345) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #350)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #350) #("here" 0 4 (:parent #354))) #(".\n" 0 2 (:parent #350))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #343))) :mode nil :granularity nil :parent #338) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #343) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #346) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #349))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #346) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #353) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #356) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #359) #("Processor" 0 9 (:parent #362)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #356)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #354) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #357) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #360) #("RAM" 0 3 (:parent #363)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #357)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #355) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #358) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #361) #("Storage" 0 7 (:parent #364)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #358)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #356) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #359) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #362) #("Network" 0 7 (:parent #365)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #359)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #357) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #360) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #363) #("Location" 0 8 (:parent #366)))) #(": Memphis TN\n" 0 13 (:parent #360))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #346) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #351))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #346) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #352))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #346) #("For more details, see the " 0 26 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #353) #("Specifications section" 0 22 (:parent #357))) #("of the Cuirass Manual.\n" 0 23 (:parent #353))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #346) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #354))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #344))) :mode nil :granularity nil :parent #338) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #347))) :mode section :granularity nil :parent #344) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #347) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #350) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #353) #("Guix channels" 0 13 (:parent #357))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #353)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #351))) :mode nil :granularity nil :parent #347) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #351) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #354) #("In order to run Cuirass via the " 0 32 (:parent #357)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #357)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #357)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #357)) #("as a " 0 5 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #357) #("G-Expression" 0 12 (:parent #365))) #("that will return a list of\n" 0 27 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #357) #("cuirass specifications" 0 22 (:parent #367))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #357))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #354)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #354) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #359)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #359)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #359)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #359) #("Cuirass specification" 0 21 (:parent #365))) #("\ndocumentation for more details.\n" 0 33 (:parent #359))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #354) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #360)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #360) #("Guix Configuration as a Channel" 0 31 (:parent #364))) #(".\n" 0 2 (:parent #360))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #352))) :mode nil :granularity nil :parent #347) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #352) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #355) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #358)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #358)) #("field of our " 0 13 (:parent #358)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #358)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #355))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #348))) :mode nil :granularity nil :parent #344) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #348) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #351) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #354)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #354) #("guix publish" 0 12 (:parent #358))) #(", which Guix provides the " 0 26 (:parent #354)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #354) #("guix-publish-service-type" 0 25 (:parent #360))) #(",\nwhich is used in the " 0 23 (:parent #354)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #354)) #("field of " 0 9 (:parent #354)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #354)) #("definition.\n" 0 12 (:parent #354))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #351)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #351) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #356))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #349))) :mode nil :granularity nil :parent #344) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #349) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #352) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #355))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #352) #("To anonymize nginx access logs, the " 0 36 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #356) #("anonip-service-type" 0 19 (:parent #360))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #356)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #356)) #("is defined.\n" 0 12 (:parent #356))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #352) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #352) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #360)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #360)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #352)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #352) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #362)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #362)) #("field of our\n" 0 13 (:parent #362)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #362)) #("declaration.\n" 0 13 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #352)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #350))) :mode nil :granularity nil :parent #344) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #350) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #353) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #356)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #354) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #357) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #360)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #360) #("letsencrypt" 0 11 (:parent #364))) #("via the " 0 8 (:parent #360)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #360) #("certbot" 0 7 (:parent #366))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #360) #("certbox-service-type" 0 20 (:parent #368))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #360)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #360)) #("field in our " 0 13 (:parent #360)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #360)) #("configuration.\n" 0 15 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #357) #("This service references " 0 24 (:parent #362)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #362)) #(", which we define below. It sends " 0 34 (:parent #362)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #362)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #357) #("Next we define a function we will use later in the " 0 51 (:parent #364)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #364) #("Configure Nginx Server Blocks" 0 29 (:parent #368))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #364))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #357)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #355)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #355) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #358) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #358)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #358) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #363))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #358) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #367) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #370)) #("\n" 0 1 (:parent #370))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #367) #(" " 0 2 (:parent #371)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #371)) #("provides a route " 0 17 (:parent #371)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #371)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #371)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #371)) #("command). Given away by the reference to " 0 41 (:parent #371)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #371) #("Nix" 0 3 (:parent #381))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #371)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #371) #("Nix Binary Cache" 0 16 (:parent #383))) #(".\n" 0 2 (:parent #371))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #367) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #372))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #367)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #367) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #374))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #367))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #368) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #371)) #("\n" 0 1 (:parent #371))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #368) #(" " 0 2 (:parent #372)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #372) #("NAR (Nix Archive Format)" 0 24 (:parent #376))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #372)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #372) #("hello" 0 5 (:parent #378))) #("package.\n" 0 9 (:parent #372))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #368) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #368)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #368)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #368) #(" The result is composed of a few parts:\n" 0 41 (:parent #376))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #368) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #380))) :mode item :granularity nil :parent #377) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #380) #("the guix store path\n" 0 20 (:parent #383)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #381))) :mode item :granularity nil :parent #377) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #381) #("a hash uniquely identifying the store item\n" 0 43 (:parent #384)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #382))) :mode item :granularity nil :parent #377) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #382) #("the package-name and version, separated by dashes\n" 0 50 (:parent #385))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #368) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #378)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #378)) #(".\n" 0 2 (:parent #378))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #368))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #369) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #372)) #("\n" 0 1 (:parent #372))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #369) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #373)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #373)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #373)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #373)) #("file.\n" 0 6 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #369)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #369)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #369) #(" If the package is not available, this would return a " 0 55 (:parent #376)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #376)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #376)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #376)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #376)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #376)) #("below.\n" 0 7 (:parent #376))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #369) #(" #+begin" 0 9 (:parent #377)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #377) #("src" 0 3 (:parent #381))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #377)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #377) #("nar" 0 3 (:parent #383))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #377)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #377) #("pass" 0 4 (:parent #385))) #("\" url \";\")\n \"client" 0 25 (:parent #377)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #377) #("body" 0 4 (:parent #387))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #377) #("buffer" 0 6 (:parent #388))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #377) #("size" 0 4 (:parent #389))) #("256k;\"\n" 0 7 (:parent #377)))))))))) :headline-offset 0 :headline-numbering nil :id-alist nil :citations nil :internal-references (("org1d65611" headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #350))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #396))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #442) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #445)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #445)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #445) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #458))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #445) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #459))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #445) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #460))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #445) #("Earlier this year " 0 18 (:parent #461)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #461) #("I announced on the guix mailing list" 0 36 (:parent #465))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #461)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #446))) :mode nil :granularity nil :parent #442) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #446) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #449) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #452))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #449) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #456) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #459) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #462) #("Improved Build Diversity" 0 24 (:parent #465)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #459)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #457) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #460) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #463) #("Reduced Latency" 0 15 (:parent #466)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #460)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #458) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #461) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #464) #("Increased Resilience" 0 20 (:parent #467)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #461)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #459) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #462) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #465) #("Community Contribution" 0 22 (:parent #468)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #462))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #449) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #454)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #454) #("here" 0 4 (:parent #458))) #(".\n" 0 2 (:parent #454))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #447))) :mode nil :granularity nil :parent #442) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #447) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #450) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #453))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #450) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #457) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #460) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #463) #("Processor" 0 9 (:parent #466)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #460)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #458) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #461) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #464) #("RAM" 0 3 (:parent #467)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #461)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #459) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #462) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #465) #("Storage" 0 7 (:parent #468)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #462)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #460) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #463) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #466) #("Network" 0 7 (:parent #469)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #463)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #461) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #464) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #467) #("Location" 0 8 (:parent #470)))) #(": Memphis TN\n" 0 13 (:parent #464))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #450) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #455))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #450) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #456))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #450) #("For more details, see the " 0 26 (:parent #457)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #457) #("Specifications section" 0 22 (:parent #461))) #("of the Cuirass Manual.\n" 0 23 (:parent #457))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #450) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #458))))) #396)) #350 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #400))) :mode nil :granularity nil :parent #396) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #400) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #403) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #406)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #406) #("guix publish" 0 12 (:parent #410))) #(", which Guix provides the " 0 26 (:parent #406)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #406) #("guix-publish-service-type" 0 25 (:parent #412))) #(",\nwhich is used in the " 0 23 (:parent #406)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #406)) #("field of " 0 9 (:parent #406)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #406)) #("definition.\n" 0 12 (:parent #406))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #403)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #403) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #408))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #401))) :mode nil :granularity nil :parent #396) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #401) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #404) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #407))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #404) #("To anonymize nginx access logs, the " 0 36 (:parent #408)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #408) #("anonip-service-type" 0 19 (:parent #412))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #408)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #408)) #("is defined.\n" 0 12 (:parent #408))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #404) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #410))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #404) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #412)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #412)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #404)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #404) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #414)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #414)) #("field of our\n" 0 13 (:parent #414)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #414)) #("declaration.\n" 0 13 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #404)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #402))) :mode nil :granularity nil :parent #396) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #402) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #405) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #408)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #406))) :mode nil :granularity nil :parent #402) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #406) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #409) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #412)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #412) #("letsencrypt" 0 11 (:parent #416))) #("via the " 0 8 (:parent #412)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #412) #("certbot" 0 7 (:parent #418))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #412)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #412) #("certbox-service-type" 0 20 (:parent #420))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #412)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #412)) #("field in our " 0 13 (:parent #412)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #412)) #("configuration.\n" 0 15 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #409) #("This service references " 0 24 (:parent #414)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #414)) #(", which we define below. It sends " 0 34 (:parent #414)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #414)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #409) #("Next we define a function we will use later in the " 0 51 (:parent #416)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #416) #("Configure Nginx Server Blocks" 0 29 (:parent #420))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #416))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #409)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #407)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #407) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #410) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #413))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #410)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #410) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #415))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #419) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #422)) #("\n" 0 1 (:parent #422))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #419) #(" " 0 2 (:parent #423)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #423)) #("provides a route " 0 17 (:parent #423)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #423)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #423)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #423)) #("command). Given away by the reference to " 0 41 (:parent #423)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #423) #("Nix" 0 3 (:parent #433))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #423)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #423) #("Nix Binary Cache" 0 16 (:parent #435))) #(".\n" 0 2 (:parent #423))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #419) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #424))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #419)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #419) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #419))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #420) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #423)) #("\n" 0 1 (:parent #423))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #420) #(" " 0 2 (:parent #424)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #424) #("NAR (Nix Archive Format)" 0 24 (:parent #428))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #424)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #424) #("hello" 0 5 (:parent #430))) #("package.\n" 0 9 (:parent #424))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #420) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #420)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #420)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #420) #(" The result is composed of a few parts:\n" 0 41 (:parent #428))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #420) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #432))) :mode item :granularity nil :parent #429) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #432) #("the guix store path\n" 0 20 (:parent #435)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #433))) :mode item :granularity nil :parent #429) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #433) #("a hash uniquely identifying the store item\n" 0 43 (:parent #436)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #434))) :mode item :granularity nil :parent #429) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #434) #("the package-name and version, separated by dashes\n" 0 50 (:parent #437))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #420) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #430)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #430)) #(".\n" 0 2 (:parent #430))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #420))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #421) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #424)) #("\n" 0 1 (:parent #424))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #421) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #425)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #425)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #425)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #425)) #("file.\n" 0 6 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #421)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #421)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #421) #(" If the package is not available, this would return a " 0 55 (:parent #428)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #428)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #428)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #428)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #428)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #428)) #("below.\n" 0 7 (:parent #428))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #421) #(" #+begin" 0 9 (:parent #429)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #429) #("src" 0 3 (:parent #433))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #429)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #429) #("nar" 0 3 (:parent #435))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #429)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #429) #("pass" 0 4 (:parent #437))) #("\" url \";\")\n \"client" 0 25 (:parent #429)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #429) #("body" 0 4 (:parent #439))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #429) #("buffer" 0 6 (:parent #440))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #429) #("size" 0 4 (:parent #441))) #("256k;\"\n" 0 7 (:parent #429)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #350) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #353) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #356) #("Guix channels" 0 13 (:parent #360))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #356)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #354) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #357) #("In order to run Cuirass via the " 0 32 (:parent #360)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #360)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #360)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #360)) #("as a " 0 5 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #360) #("G-Expression" 0 12 (:parent #368))) #("that will return a list of\n" 0 27 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #360) #("cuirass specifications" 0 22 (:parent #370))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #357)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #357) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #362)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #362)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #362)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #362) #("Cuirass specification" 0 21 (:parent #368))) #("\ndocumentation for more details.\n" 0 33 (:parent #362))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #357) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #363)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #363) #("Guix Configuration as a Channel" 0 31 (:parent #367))) #(".\n" 0 2 (:parent #363))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #355) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #358) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #361)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #361)) #("field of our " 0 13 (:parent #361)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #361)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #358))))) ((other "Cuirass" "-" "Building" "Packages") . 30823953) ((headline "Cuirass" "-" "Building" "Packages") . 30823953) ("org46b8c57" headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #353))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #399) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #402)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #402)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #402) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #415))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #402) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #416))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #402) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #417))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #402) #("Earlier this year " 0 18 (:parent #418)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #418) #("I announced on the guix mailing list" 0 36 (:parent #422))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #418)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #403))) :mode nil :granularity nil :parent #399) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #403) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #406) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #409))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #406) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #413) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #416) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #419) #("Improved Build Diversity" 0 24 (:parent #422)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #416)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #414) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #417) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #420) #("Reduced Latency" 0 15 (:parent #423)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #417)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #415) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #418) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #421) #("Increased Resilience" 0 20 (:parent #424)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #418)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #416) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #419) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #422) #("Community Contribution" 0 22 (:parent #425)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #419))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #406) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #411)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #411) #("here" 0 4 (:parent #415))) #(".\n" 0 2 (:parent #411))))) #353 (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #405))) :mode nil :granularity nil :parent #399) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #408))) :mode section :granularity nil :parent #405) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #408) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #411) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #414)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #414) #("Guix channels" 0 13 (:parent #418))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #414)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #412) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #415) #("In order to run Cuirass via the " 0 32 (:parent #418)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #418)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #418)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #418)) #("as a " 0 5 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #418) #("G-Expression" 0 12 (:parent #426))) #("that will return a list of\n" 0 27 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #418) #("cuirass specifications" 0 22 (:parent #428))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #415)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #415) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #420)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #420)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #420) #("Cuirass specification" 0 21 (:parent #426))) #("\ndocumentation for more details.\n" 0 33 (:parent #420))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #415) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #421)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #421) #("Guix Configuration as a Channel" 0 31 (:parent #425))) #(".\n" 0 2 (:parent #421))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #413) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #416) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #419)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #419)) #("field of our " 0 13 (:parent #419)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #419)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #416))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #409))) :mode nil :granularity nil :parent #405) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #409) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #412) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #415)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #415) #("guix publish" 0 12 (:parent #419))) #(", which Guix provides the " 0 26 (:parent #415)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #415) #("guix-publish-service-type" 0 25 (:parent #421))) #(",\nwhich is used in the " 0 23 (:parent #415)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #415)) #("field of " 0 9 (:parent #415)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #415)) #("definition.\n" 0 12 (:parent #415))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #412)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #412) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #417))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #410))) :mode nil :granularity nil :parent #405) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #410) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #413) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #416))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #413) #("To anonymize nginx access logs, the " 0 36 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #417) #("anonip-service-type" 0 19 (:parent #421))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #417)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #417)) #("is defined.\n" 0 12 (:parent #417))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #413) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #413) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #421)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #421)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #413)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #413) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #423)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #423)) #("field of our\n" 0 13 (:parent #423)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #423)) #("declaration.\n" 0 13 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #413)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #411))) :mode nil :granularity nil :parent #405) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #411) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #414) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #417)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #415) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #418) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #421)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #421) #("letsencrypt" 0 11 (:parent #425))) #("via the " 0 8 (:parent #421)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #421) #("certbot" 0 7 (:parent #427))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #421) #("certbox-service-type" 0 20 (:parent #429))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #421)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #421)) #("field in our " 0 13 (:parent #421)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #421)) #("configuration.\n" 0 15 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #418) #("This service references " 0 24 (:parent #423)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #423)) #(", which we define below. It sends " 0 34 (:parent #423)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #423)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #418) #("Next we define a function we will use later in the " 0 51 (:parent #425)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #425) #("Configure Nginx Server Blocks" 0 29 (:parent #429))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #418)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #416)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #416) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #419) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #419)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #419) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #424))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #419) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #428) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #431)) #("\n" 0 1 (:parent #431))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #428) #(" " 0 2 (:parent #432)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #432)) #("provides a route " 0 17 (:parent #432)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #432)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #432)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #432)) #("command). Given away by the reference to " 0 41 (:parent #432)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #432) #("Nix" 0 3 (:parent #442))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #432)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #432) #("Nix Binary Cache" 0 16 (:parent #444))) #(".\n" 0 2 (:parent #432))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #428) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #433))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #428)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #428) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #435))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #428))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #429) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #432)) #("\n" 0 1 (:parent #432))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #429) #(" " 0 2 (:parent #433)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #433) #("NAR (Nix Archive Format)" 0 24 (:parent #437))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #433)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #433) #("hello" 0 5 (:parent #439))) #("package.\n" 0 9 (:parent #433))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #429) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #429)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #429)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #429) #(" The result is composed of a few parts:\n" 0 41 (:parent #437))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #429) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #441))) :mode item :granularity nil :parent #438) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #441) #("the guix store path\n" 0 20 (:parent #444)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #442))) :mode item :granularity nil :parent #438) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #442) #("a hash uniquely identifying the store item\n" 0 43 (:parent #445)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #443))) :mode item :granularity nil :parent #438) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #443) #("the package-name and version, separated by dashes\n" 0 50 (:parent #446))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #429) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #439)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #439)) #(".\n" 0 2 (:parent #439))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #429))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #430) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #433)) #("\n" 0 1 (:parent #433))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #430) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #434)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #434)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #434)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #434)) #("file.\n" 0 6 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #430)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #430)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #430) #(" If the package is not available, this would return a " 0 55 (:parent #437)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #437)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #437)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #437)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #437)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #437)) #("below.\n" 0 7 (:parent #437))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #430) #(" #+begin" 0 9 (:parent #438)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #438) #("src" 0 3 (:parent #442))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #438)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #438) #("nar" 0 3 (:parent #444))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #438)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #438) #("pass" 0 4 (:parent #446))) #("\" url \";\")\n \"client" 0 25 (:parent #438)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #438) #("body" 0 4 (:parent #448))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #438) #("buffer" 0 6 (:parent #449))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #438) #("size" 0 4 (:parent #450))) #("256k;\"\n" 0 7 (:parent #438))))))))))) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #353) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #356) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #359))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #356) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #363) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #366) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #369) #("Processor" 0 9 (:parent #372)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #366)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #364) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #367) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #370) #("RAM" 0 3 (:parent #373)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #367)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #365) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #368) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #371) #("Storage" 0 7 (:parent #374)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #368)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #366) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #369) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #372) #("Network" 0 7 (:parent #375)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #369)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #367) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #370) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #373) #("Location" 0 8 (:parent #376)))) #(": Memphis TN\n" 0 13 (:parent #370))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #356) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #361))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #356) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #362))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #356) #("For more details, see the " 0 26 (:parent #363)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #363) #("Specifications section" 0 22 (:parent #367))) #("of the Cuirass Manual.\n" 0 23 (:parent #363))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #356) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #364))))) ((other "Hardware" "and" "Infrastructure") . 74157143) ((headline "Hardware" "and" "Infrastructure") . 74157143) ("orgcc40a3d" headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #356))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #402) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #405)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #405)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #405) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #418))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #405) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #419))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #405) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #420))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #405) #("Earlier this year " 0 18 (:parent #421)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #421) #("I announced on the guix mailing list" 0 36 (:parent #425))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #421)))) #356 (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #407) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #410) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #413))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #417) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #420) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #423) #("Processor" 0 9 (:parent #426)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #420)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #418) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #421) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #424) #("RAM" 0 3 (:parent #427)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #421)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #419) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #422) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #425) #("Storage" 0 7 (:parent #428)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #422)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #420) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #423) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #426) #("Network" 0 7 (:parent #429)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #423)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #421) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #424) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #427) #("Location" 0 8 (:parent #430)))) #(": Memphis TN\n" 0 13 (:parent #424))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #410) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #415))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #410) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #416))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #410) #("For more details, see the " 0 26 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #417) #("Specifications section" 0 22 (:parent #421))) #("of the Cuirass Manual.\n" 0 23 (:parent #417))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #410) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #418))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #408))) :mode nil :granularity nil :parent #402) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #411))) :mode section :granularity nil :parent #408) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #411) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #414) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #417) #("Guix channels" 0 13 (:parent #421))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #417)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #415) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #418) #("In order to run Cuirass via the " 0 32 (:parent #421)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #421)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #421)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #421)) #("as a " 0 5 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #421) #("G-Expression" 0 12 (:parent #429))) #("that will return a list of\n" 0 27 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #421) #("cuirass specifications" 0 22 (:parent #431))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #418)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #418) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #423)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #423)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #423)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #423) #("Cuirass specification" 0 21 (:parent #429))) #("\ndocumentation for more details.\n" 0 33 (:parent #423))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #418) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #424)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #424) #("Guix Configuration as a Channel" 0 31 (:parent #428))) #(".\n" 0 2 (:parent #424))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #416) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #419) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #422)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #422)) #("field of our " 0 13 (:parent #422)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #422)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #419))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #412) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #415) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #418) #("guix publish" 0 12 (:parent #422))) #(", which Guix provides the " 0 26 (:parent #418)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #418) #("guix-publish-service-type" 0 25 (:parent #424))) #(",\nwhich is used in the " 0 23 (:parent #418)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #418)) #("field of " 0 9 (:parent #418)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #418)) #("definition.\n" 0 12 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #415)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #415) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #420))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #413) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #416) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #419))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #416) #("To anonymize nginx access logs, the " 0 36 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #420) #("anonip-service-type" 0 19 (:parent #424))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #420)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #420)) #("is defined.\n" 0 12 (:parent #420))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #416) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #416) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #424)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #424)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #416)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #416) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #426)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #426)) #("field of our\n" 0 13 (:parent #426)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #426)) #("declaration.\n" 0 13 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #416)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #414))) :mode nil :granularity nil :parent #408) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #414) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #417) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #420)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #418))) :mode nil :granularity nil :parent #414) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #418) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #421) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #424)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #424) #("letsencrypt" 0 11 (:parent #428))) #("via the " 0 8 (:parent #424)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #424) #("certbot" 0 7 (:parent #430))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #424)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #424) #("certbox-service-type" 0 20 (:parent #432))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #424)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #424)) #("field in our " 0 13 (:parent #424)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #424)) #("configuration.\n" 0 15 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #421) #("This service references " 0 24 (:parent #426)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #426)) #(", which we define below. It sends " 0 34 (:parent #426)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #426)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #421) #("Next we define a function we will use later in the " 0 51 (:parent #428)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #428) #("Configure Nginx Server Blocks" 0 29 (:parent #432))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #428))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #421)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #419)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #419))) :mode nil :granularity nil :parent #414) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #419) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #422) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #422)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #422) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #427))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #422) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #431) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #434)) #("\n" 0 1 (:parent #434))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #431) #(" " 0 2 (:parent #435)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #435)) #("provides a route " 0 17 (:parent #435)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #435)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #435)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #435)) #("command). Given away by the reference to " 0 41 (:parent #435)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #435) #("Nix" 0 3 (:parent #445))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #435)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #435) #("Nix Binary Cache" 0 16 (:parent #447))) #(".\n" 0 2 (:parent #435))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #431) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #436))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #431)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #431) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #438))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #431))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #432) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #435)) #("\n" 0 1 (:parent #435))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #432) #(" " 0 2 (:parent #436)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #436) #("NAR (Nix Archive Format)" 0 24 (:parent #440))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #436)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #436) #("hello" 0 5 (:parent #442))) #("package.\n" 0 9 (:parent #436))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #432) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #432)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #432)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #432) #(" The result is composed of a few parts:\n" 0 41 (:parent #440))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #432) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #444))) :mode item :granularity nil :parent #441) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #444) #("the guix store path\n" 0 20 (:parent #447)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #445))) :mode item :granularity nil :parent #441) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #445) #("a hash uniquely identifying the store item\n" 0 43 (:parent #448)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #446))) :mode item :granularity nil :parent #441) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #446) #("the package-name and version, separated by dashes\n" 0 50 (:parent #449))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #432) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #442)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #442)) #(".\n" 0 2 (:parent #442))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #432))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #433) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #436)) #("\n" 0 1 (:parent #436))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #433) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #437)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #437)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #437)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #437)) #("file.\n" 0 6 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #433)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #433)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #433) #(" If the package is not available, this would return a " 0 55 (:parent #440)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #440)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #440)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #440)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #440)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #440)) #("below.\n" 0 7 (:parent #440))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #433) #(" #+begin" 0 9 (:parent #441)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #441) #("src" 0 3 (:parent #445))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #441)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #441) #("nar" 0 3 (:parent #447))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #441)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #441) #("pass" 0 4 (:parent #449))) #("\" url \";\")\n \"client" 0 25 (:parent #441)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #441) #("body" 0 4 (:parent #451))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #441) #("buffer" 0 6 (:parent #452))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #441) #("size" 0 4 (:parent #453))) #("256k;\"\n" 0 7 (:parent #441))))))))))) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #356) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #359) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #362))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #359) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #366) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #369) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #372) #("Improved Build Diversity" 0 24 (:parent #375)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #369)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #367) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #370) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #373) #("Reduced Latency" 0 15 (:parent #376)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #370)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #368) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #371) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #374) #("Increased Resilience" 0 20 (:parent #377)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #371)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #369) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #372) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #375) #("Community Contribution" 0 22 (:parent #378)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #372))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #359) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #364)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #364) #("here" 0 4 (:parent #368))) #(".\n" 0 2 (:parent #364))))) ((other "Why" "Build" "Another" "Substitute" "Server?") . 214174269) ((headline "Why" "Build" "Another" "Substitute" "Server?") . 214174269)) :resolve-fuzzy-link-cache #))
#f(compiled-function (element) #)((headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #0))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #46))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #92))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #138) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #141)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #141)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #141)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #141) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #154))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #141) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #155))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #141) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #156))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #141) #("Earlier this year " 0 18 (:parent #157)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #157) #("I announced on the guix mailing list" 0 36 (:parent #161))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #157)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #142))) :mode nil :granularity nil :parent #138) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #142) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #145) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #148))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #145) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #149) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #152) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #155) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #158) #("Improved Build Diversity" 0 24 (:parent #161)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #155)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #149) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #153) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #156) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #159) #("Reduced Latency" 0 15 (:parent #162)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #156)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #149) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #154) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #157) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #160) #("Increased Resilience" 0 20 (:parent #163)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #157)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #149) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #155) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #158) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #161) #("Community Contribution" 0 22 (:parent #164)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #158))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #145) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #150)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #150) #("here" 0 4 (:parent #154))) #(".\n" 0 2 (:parent #150))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #143))) :mode nil :granularity nil :parent #138) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #143) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #146) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #149))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #146) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #153) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #156) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #159) #("Processor" 0 9 (:parent #162)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #156)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #154) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #157) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #160) #("RAM" 0 3 (:parent #163)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #157)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #155) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #158) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #161) #("Storage" 0 7 (:parent #164)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #158)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #156) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #159) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #162) #("Network" 0 7 (:parent #165)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #159)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #150) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #157) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #160) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #163) #("Location" 0 8 (:parent #166)))) #(": Memphis TN\n" 0 13 (:parent #160))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #146) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #151))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #146) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #152))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #146) #("For more details, see the " 0 26 (:parent #153)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #153) #("Specifications section" 0 22 (:parent #157))) #("of the Cuirass Manual.\n" 0 23 (:parent #153))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #146) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #154))))) #92)) #46 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #96))) :mode nil :granularity nil :parent #92) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #96) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #99) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #102)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #102) #("guix publish" 0 12 (:parent #106))) #(", which Guix provides the " 0 26 (:parent #102)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #102) #("guix-publish-service-type" 0 25 (:parent #108))) #(",\nwhich is used in the " 0 23 (:parent #102)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #102)) #("field of " 0 9 (:parent #102)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #102)) #("definition.\n" 0 12 (:parent #102))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #99)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #99) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #104))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #97))) :mode nil :granularity nil :parent #92) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #97) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #100) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #103))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #100) #("To anonymize nginx access logs, the " 0 36 (:parent #104)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #104) #("anonip-service-type" 0 19 (:parent #108))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #104)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #104)) #("is defined.\n" 0 12 (:parent #104))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #100)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #100) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #106))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #100)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #100) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #108)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #108)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #108))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #100)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #100) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #110)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #110)) #("field of our\n" 0 13 (:parent #110)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #110)) #("declaration.\n" 0 13 (:parent #110))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #100)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #98))) :mode nil :granularity nil :parent #92) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #98) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #101) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #104)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #102))) :mode nil :granularity nil :parent #98) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #102) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #105) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #108)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #108) #("letsencrypt" 0 11 (:parent #112))) #("via the " 0 8 (:parent #108)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #108) #("certbot" 0 7 (:parent #114))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #108)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #108) #("certbox-service-type" 0 20 (:parent #116))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #108)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #108)) #("field in our " 0 13 (:parent #108)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #108)) #("configuration.\n" 0 15 (:parent #108))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #105)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #105) #("This service references " 0 24 (:parent #110)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #110)) #(", which we define below. It sends " 0 34 (:parent #110)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #110)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #110))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #105)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #105) #("Next we define a function we will use later in the " 0 51 (:parent #112)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #112) #("Configure Nginx Server Blocks" 0 29 (:parent #116))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #112))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #105)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #103)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #103))) :mode nil :granularity nil :parent #98) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #103) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #106) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #109))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #106)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #106) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #111))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #106) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #112) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #115) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #118)) #("\n" 0 1 (:parent #118))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #115) #(" " 0 2 (:parent #119)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #119)) #("provides a route " 0 17 (:parent #119)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #119)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #119)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #119)) #("command). Given away by the reference to " 0 41 (:parent #119)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #119) #("Nix" 0 3 (:parent #129))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #119)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #119) #("Nix Binary Cache" 0 16 (:parent #131))) #(".\n" 0 2 (:parent #119))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #115) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #120))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #115)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #115) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #122))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #115))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #112) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #116) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #119)) #("\n" 0 1 (:parent #119))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #116) #(" " 0 2 (:parent #120)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #120) #("NAR (Nix Archive Format)" 0 24 (:parent #124))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #120)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #120) #("hello" 0 5 (:parent #126))) #("package.\n" 0 9 (:parent #120))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #116) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #121))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #116)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #116)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #116) #(" The result is composed of a few parts:\n" 0 41 (:parent #124))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #116) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #128))) :mode item :granularity nil :parent #125) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #128) #("the guix store path\n" 0 20 (:parent #131)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #129))) :mode item :granularity nil :parent #125) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #129) #("a hash uniquely identifying the store item\n" 0 43 (:parent #132)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #130))) :mode item :granularity nil :parent #125) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #130) #("the package-name and version, separated by dashes\n" 0 50 (:parent #133))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #116) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #126)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #126)) #(".\n" 0 2 (:parent #126))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #116))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #112) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #117) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #120)) #("\n" 0 1 (:parent #120))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #117) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #121)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #121)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #121)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #121)) #("file.\n" 0 6 (:parent #121))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #117)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #117)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #117) #(" If the package is not available, this would return a " 0 55 (:parent #124)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #124)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #124)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #124)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #124)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #124)) #("below.\n" 0 7 (:parent #124))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #117) #(" #+begin" 0 9 (:parent #125)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #125) #("src" 0 3 (:parent #129))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #125)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #125) #("nar" 0 3 (:parent #131))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #125)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #125) #("pass" 0 4 (:parent #133))) #("\" url \";\")\n \"client" 0 25 (:parent #125)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #125) #("body" 0 4 (:parent #135))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #125) #("buffer" 0 6 (:parent #136))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #125) #("size" 0 4 (:parent #137))) #("256k;\"\n" 0 7 (:parent #125)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #46) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #49) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #52)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #52) #("Guix channels" 0 13 (:parent #56))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #52)))) #0 (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #51))) :mode nil :granularity nil :parent #46) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #51) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #54) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #57)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #57)) #("field of our " 0 13 (:parent #57)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #57)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #57))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #54)))))) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #0) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #3) #("In order to run Cuirass via the " 0 32 (:parent #6)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #6)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #6)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #6)) #("as a " 0 5 (:parent #6)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #6) #("G-Expression" 0 12 (:parent #14))) #("that will return a list of\n" 0 27 (:parent #6)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #6) #("cuirass specifications" 0 22 (:parent #16))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #6))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #3)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #3) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #8)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #8)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #8)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #8) #("Cuirass specification" 0 21 (:parent #14))) #("\ndocumentation for more details.\n" 0 33 (:parent #8))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #3) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #9)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #9) #("Guix Configuration as a Channel" 0 31 (:parent #13))) #(".\n" 0 2 (:parent #9))))))
mapconcat(#f(compiled-function (element) #) ((section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #25))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #71))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #117) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #120)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #120)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #120)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #120)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #120)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #120)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #120)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #120)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #120)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #120)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #120) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #133))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #120) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #134))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #120) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #135))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #120) #("Earlier this year " 0 18 (:parent #136)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #136) #("I announced on the guix mailing list" 0 36 (:parent #140))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #136)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #121))) :mode nil :granularity nil :parent #117) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #121) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #124) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #127))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #124) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #128) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #131) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #134) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #137) #("Improved Build Diversity" 0 24 (:parent #140)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #134)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #128) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #132) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #135) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #138) #("Reduced Latency" 0 15 (:parent #141)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #135)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #128) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #133) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #136) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #139) #("Increased Resilience" 0 20 (:parent #142)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #136)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #128) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #134) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #137) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #140) #("Community Contribution" 0 22 (:parent #143)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #137))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #124) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #129)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #129) #("here" 0 4 (:parent #133))) #(".\n" 0 2 (:parent #129))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #122))) :mode nil :granularity nil :parent #117) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #122) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #125) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #128))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #125) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #129) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #132) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #135) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #138) #("Processor" 0 9 (:parent #141)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #135)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #129) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #133) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #136) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #139) #("RAM" 0 3 (:parent #142)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #136)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #129) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #134) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #137) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #140) #("Storage" 0 7 (:parent #143)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #137)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #129) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #135) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #138) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #141) #("Network" 0 7 (:parent #144)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #138)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #129) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #136) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #139) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #142) #("Location" 0 8 (:parent #145)))) #(": Memphis TN\n" 0 13 (:parent #139))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #125) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #130))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #125) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #131))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #125) #("For more details, see the " 0 26 (:parent #132)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #132) #("Specifications section" 0 22 (:parent #136))) #("of the Cuirass Manual.\n" 0 23 (:parent #132))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #125) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #133))))) #71)) #25 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #75))) :mode nil :granularity nil :parent #71) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #75) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #78) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #81)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #81) #("guix publish" 0 12 (:parent #85))) #(", which Guix provides the " 0 26 (:parent #81)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #81) #("guix-publish-service-type" 0 25 (:parent #87))) #(",\nwhich is used in the " 0 23 (:parent #81)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #81)) #("field of " 0 9 (:parent #81)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #81)) #("definition.\n" 0 12 (:parent #81))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #78)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #78) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #83))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #76))) :mode nil :granularity nil :parent #71) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #76) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #79) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #82))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #79) #("To anonymize nginx access logs, the " 0 36 (:parent #83)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #83) #("anonip-service-type" 0 19 (:parent #87))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #83)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #83)) #("is defined.\n" 0 12 (:parent #83))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #79)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #79) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #85))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #79)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #79) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #87)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #87)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #87))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #79)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #79) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #89)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #89)) #("field of our\n" 0 13 (:parent #89)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #89)) #("declaration.\n" 0 13 (:parent #89))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #79)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #77))) :mode nil :granularity nil :parent #71) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #77) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #80) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #83)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #81))) :mode nil :granularity nil :parent #77) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #81) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #84) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #87)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #87) #("letsencrypt" 0 11 (:parent #91))) #("via the " 0 8 (:parent #87)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #87) #("certbot" 0 7 (:parent #93))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #87)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #87) #("certbox-service-type" 0 20 (:parent #95))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #87)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #87)) #("field in our " 0 13 (:parent #87)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #87)) #("configuration.\n" 0 15 (:parent #87))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #84)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #84) #("This service references " 0 24 (:parent #89)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #89)) #(", which we define below. It sends " 0 34 (:parent #89)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #89)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #89))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #84)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #84) #("Next we define a function we will use later in the " 0 51 (:parent #91)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #91) #("Configure Nginx Server Blocks" 0 29 (:parent #95))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #91))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #84)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #82)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #82))) :mode nil :granularity nil :parent #77) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #82) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #85) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #88))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #85)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #85) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #90))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #85) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #91) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #94) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #97)) #("\n" 0 1 (:parent #97))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #94) #(" " 0 2 (:parent #98)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #98)) #("provides a route " 0 17 (:parent #98)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #98)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #98)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #98)) #("command). Given away by the reference to " 0 41 (:parent #98)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #98) #("Nix" 0 3 (:parent #108))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #98)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #98) #("Nix Binary Cache" 0 16 (:parent #110))) #(".\n" 0 2 (:parent #98))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #94) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #99))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #94)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #94) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #101))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #94))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #91) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #95) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #98)) #("\n" 0 1 (:parent #98))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #95) #(" " 0 2 (:parent #99)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #99) #("NAR (Nix Archive Format)" 0 24 (:parent #103))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #99)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #99) #("hello" 0 5 (:parent #105))) #("package.\n" 0 9 (:parent #99))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #95) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #100))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #95)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #95)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #95) #(" The result is composed of a few parts:\n" 0 41 (:parent #103))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #95) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #107))) :mode item :granularity nil :parent #104) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #107) #("the guix store path\n" 0 20 (:parent #110)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #108))) :mode item :granularity nil :parent #104) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #108) #("a hash uniquely identifying the store item\n" 0 43 (:parent #111)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #109))) :mode item :granularity nil :parent #104) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #109) #("the package-name and version, separated by dashes\n" 0 50 (:parent #112))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #95) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #105)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #105)) #(".\n" 0 2 (:parent #105))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #95))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #91) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #96) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #99)) #("\n" 0 1 (:parent #99))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #96) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #100)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #100)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #100)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #100)) #("file.\n" 0 6 (:parent #100))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #96)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #96)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #96) #(" If the package is not available, this would return a " 0 55 (:parent #103)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #103)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #103)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #103)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #103)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #103)) #("below.\n" 0 7 (:parent #103))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #96) #(" #+begin" 0 9 (:parent #104)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #104) #("src" 0 3 (:parent #108))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #104)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #104) #("nar" 0 3 (:parent #110))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #104)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #104) #("pass" 0 4 (:parent #112))) #("\" url \";\")\n \"client" 0 25 (:parent #104)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #104) #("body" 0 4 (:parent #114))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #104) #("buffer" 0 6 (:parent #115))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #104) #("size" 0 4 (:parent #116))) #("256k;\"\n" 0 7 (:parent #104)))))))))) . #0)) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #1) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #4)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #4) #("Guix channels" 0 13 (:parent #8))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #4)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #2))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #48))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #94))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #140) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #143)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #143)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #143)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #143)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #143)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #143)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #143)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #143)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #143)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #143)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #143) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #156))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #143) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #157))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #143) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #158))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #143) #("Earlier this year " 0 18 (:parent #159)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #159) #("I announced on the guix mailing list" 0 36 (:parent #163))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #159)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #144))) :mode nil :granularity nil :parent #140) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #144) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #147) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #150))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #147) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #151) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #154) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #157) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #160) #("Improved Build Diversity" 0 24 (:parent #163)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #157)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #151) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #155) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #158) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #161) #("Reduced Latency" 0 15 (:parent #164)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #158)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #151) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #156) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #159) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #162) #("Increased Resilience" 0 20 (:parent #165)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #159)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #151) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #157) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #160) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #163) #("Community Contribution" 0 22 (:parent #166)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #160))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #147) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #152)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #152) #("here" 0 4 (:parent #156))) #(".\n" 0 2 (:parent #152))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #145))) :mode nil :granularity nil :parent #140) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #145) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #148) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #151))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #148) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #155) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #158) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #161) #("Processor" 0 9 (:parent #164)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #158)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #156) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #159) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #162) #("RAM" 0 3 (:parent #165)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #159)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #157) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #160) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #163) #("Storage" 0 7 (:parent #166)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #160)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #158) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #161) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #164) #("Network" 0 7 (:parent #167)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #161)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #159) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #162) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #165) #("Location" 0 8 (:parent #168)))) #(": Memphis TN\n" 0 13 (:parent #162))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #148) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #153))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #148) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #154))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #148) #("For more details, see the " 0 26 (:parent #155)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #155) #("Specifications section" 0 22 (:parent #159))) #("of the Cuirass Manual.\n" 0 23 (:parent #155))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #148) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #156))))) #94)) #48 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #98))) :mode nil :granularity nil :parent #94) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #98) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #101) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #104)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #104) #("guix publish" 0 12 (:parent #108))) #(", which Guix provides the " 0 26 (:parent #104)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #104) #("guix-publish-service-type" 0 25 (:parent #110))) #(",\nwhich is used in the " 0 23 (:parent #104)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #104)) #("field of " 0 9 (:parent #104)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #104)) #("definition.\n" 0 12 (:parent #104))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #101)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #101) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #106))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #99))) :mode nil :granularity nil :parent #94) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #99) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #102) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #105))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #102) #("To anonymize nginx access logs, the " 0 36 (:parent #106)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #106) #("anonip-service-type" 0 19 (:parent #110))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #106)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #106)) #("is defined.\n" 0 12 (:parent #106))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #102)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #102) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #108))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #102)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #102) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #110)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #110)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #110))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #102)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #102) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #112)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #112)) #("field of our\n" 0 13 (:parent #112)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #112)) #("declaration.\n" 0 13 (:parent #112))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #102)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #100))) :mode nil :granularity nil :parent #94) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #100) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #103) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #106)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #104))) :mode nil :granularity nil :parent #100) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #104) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #107) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #110)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #110) #("letsencrypt" 0 11 (:parent #114))) #("via the " 0 8 (:parent #110)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #110) #("certbot" 0 7 (:parent #116))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #110)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #110) #("certbox-service-type" 0 20 (:parent #118))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #110)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #110)) #("field in our " 0 13 (:parent #110)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #110)) #("configuration.\n" 0 15 (:parent #110))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #107)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #107) #("This service references " 0 24 (:parent #112)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #112)) #(", which we define below. It sends " 0 34 (:parent #112)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #112)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #112))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #107)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #107) #("Next we define a function we will use later in the " 0 51 (:parent #114)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #114) #("Configure Nginx Server Blocks" 0 29 (:parent #118))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #114))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #107)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #105)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #105))) :mode nil :granularity nil :parent #100) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #105) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #108) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #111))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #108)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #108) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #113))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #108) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #114) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #117) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #120)) #("\n" 0 1 (:parent #120))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #117) #(" " 0 2 (:parent #121)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #121)) #("provides a route " 0 17 (:parent #121)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #121)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #121)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #121)) #("command). Given away by the reference to " 0 41 (:parent #121)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #121) #("Nix" 0 3 (:parent #131))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #121)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #121) #("Nix Binary Cache" 0 16 (:parent #133))) #(".\n" 0 2 (:parent #121))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #117) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #122))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #117)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #117) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #124))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #117))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #114) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #118) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #121)) #("\n" 0 1 (:parent #121))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #118) #(" " 0 2 (:parent #122)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #122) #("NAR (Nix Archive Format)" 0 24 (:parent #126))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #122)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #122) #("hello" 0 5 (:parent #128))) #("package.\n" 0 9 (:parent #122))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #118) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #123))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #118)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #118)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #118) #(" The result is composed of a few parts:\n" 0 41 (:parent #126))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #118) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #130))) :mode item :granularity nil :parent #127) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #130) #("the guix store path\n" 0 20 (:parent #133)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #131))) :mode item :granularity nil :parent #127) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #131) #("a hash uniquely identifying the store item\n" 0 43 (:parent #134)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #132))) :mode item :granularity nil :parent #127) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #132) #("the package-name and version, separated by dashes\n" 0 50 (:parent #135))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #118) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #128)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #128)) #(".\n" 0 2 (:parent #128))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #118))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #114) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #119) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #122)) #("\n" 0 1 (:parent #122))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #119) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #123)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #123)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #123)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #123)) #("file.\n" 0 6 (:parent #123))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #119)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #119)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #119) #(" If the package is not available, this would return a " 0 55 (:parent #126)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #126)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #126)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #126)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #126)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #126)) #("below.\n" 0 7 (:parent #126))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #119) #(" #+begin" 0 9 (:parent #127)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #127) #("src" 0 3 (:parent #131))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #127)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #127) #("nar" 0 3 (:parent #133))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #127)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #127) #("pass" 0 4 (:parent #135))) #("\" url \";\")\n \"client" 0 25 (:parent #127)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #127) #("body" 0 4 (:parent #137))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #127) #("buffer" 0 6 (:parent #138))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #127) #("size" 0 4 (:parent #139))) #("256k;\"\n" 0 7 (:parent #127)))))))))) . #0)) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #2) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #5) #("In order to run Cuirass via the " 0 32 (:parent #8)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #8)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #8)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #8)) #("as a " 0 5 (:parent #8)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #8) #("G-Expression" 0 12 (:parent #16))) #("that will return a list of\n" 0 27 (:parent #8)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #8) #("cuirass specifications" 0 22 (:parent #18))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #8))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #5)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #5) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #10)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #10)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #10)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #10) #("Cuirass specification" 0 21 (:parent #16))) #("\ndocumentation for more details.\n" 0 33 (:parent #10))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #5) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #11)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #11) #("Guix Configuration as a Channel" 0 31 (:parent #15))) #(".\n" 0 2 (:parent #11))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #3))) :mode nil :granularity nil :parent (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #49))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #95))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #141) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #144)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #144)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #144)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #144)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #144)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #144)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #144)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #144)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #144)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #144)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #144) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #157))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #144) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #158))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #144) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #159))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #144) #("Earlier this year " 0 18 (:parent #160)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #160) #("I announced on the guix mailing list" 0 36 (:parent #164))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #160)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #145))) :mode nil :granularity nil :parent #141) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #145) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #148) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #151))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #148) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #155) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #158) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #161) #("Improved Build Diversity" 0 24 (:parent #164)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #158)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #156) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #159) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #162) #("Reduced Latency" 0 15 (:parent #165)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #159)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #157) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #160) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #163) #("Increased Resilience" 0 20 (:parent #166)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #160)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #152) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #158) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #161) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #164) #("Community Contribution" 0 22 (:parent #167)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #161))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #148) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #153)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #153) #("here" 0 4 (:parent #157))) #(".\n" 0 2 (:parent #153))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #146))) :mode nil :granularity nil :parent #141) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #146) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #149) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #152))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #149) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #153) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #156) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #159) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #162) #("Processor" 0 9 (:parent #165)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #159)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #153) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #157) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #160) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #163) #("RAM" 0 3 (:parent #166)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #160)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #153) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #158) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #161) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #164) #("Storage" 0 7 (:parent #167)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #161)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #153) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #159) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #162) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #165) #("Network" 0 7 (:parent #168)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #162)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #153) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #160) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #163) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #166) #("Location" 0 8 (:parent #169)))) #(": Memphis TN\n" 0 13 (:parent #163))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #149) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #154))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #149) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #155))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #149) #("For more details, see the " 0 26 (:parent #156)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #156) #("Specifications section" 0 22 (:parent #160))) #("of the Cuirass Manual.\n" 0 23 (:parent #156))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #149) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #157))))) #95)) #49 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #99))) :mode nil :granularity nil :parent #95) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #99) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #102) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #105)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #105) #("guix publish" 0 12 (:parent #109))) #(", which Guix provides the " 0 26 (:parent #105)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #105) #("guix-publish-service-type" 0 25 (:parent #111))) #(",\nwhich is used in the " 0 23 (:parent #105)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #105)) #("field of " 0 9 (:parent #105)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #105)) #("definition.\n" 0 12 (:parent #105))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #102)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #102) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #107))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #100))) :mode nil :granularity nil :parent #95) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #100) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #103) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #106))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #103) #("To anonymize nginx access logs, the " 0 36 (:parent #107)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #107) #("anonip-service-type" 0 19 (:parent #111))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #107)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #107)) #("is defined.\n" 0 12 (:parent #107))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #103)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #103) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #109))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #103)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #103) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #111)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #111)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #111))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #103)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #103) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #113)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #113)) #("field of our\n" 0 13 (:parent #113)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #113)) #("declaration.\n" 0 13 (:parent #113))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #103)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #101))) :mode nil :granularity nil :parent #95) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #101) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #104) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #107)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #105))) :mode nil :granularity nil :parent #101) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #105) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #108) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #111)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #111) #("letsencrypt" 0 11 (:parent #115))) #("via the " 0 8 (:parent #111)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #111) #("certbot" 0 7 (:parent #117))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #111)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #111) #("certbox-service-type" 0 20 (:parent #119))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #111)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #111)) #("field in our " 0 13 (:parent #111)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #111)) #("configuration.\n" 0 15 (:parent #111))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #108)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #108) #("This service references " 0 24 (:parent #113)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #113)) #(", which we define below. It sends " 0 34 (:parent #113)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #113)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #113))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #108)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #108) #("Next we define a function we will use later in the " 0 51 (:parent #115)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #115) #("Configure Nginx Server Blocks" 0 29 (:parent #119))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #115))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #108)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #106)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #106))) :mode nil :granularity nil :parent #101) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #106) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #109) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #112))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #109)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #109) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #114))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #109) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #115) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #118) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #121)) #("\n" 0 1 (:parent #121))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #118) #(" " 0 2 (:parent #122)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #122)) #("provides a route " 0 17 (:parent #122)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #122)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #122)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #122)) #("command). Given away by the reference to " 0 41 (:parent #122)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #122) #("Nix" 0 3 (:parent #132))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #122)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #122) #("Nix Binary Cache" 0 16 (:parent #134))) #(".\n" 0 2 (:parent #122))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #118) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #123))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #118)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #118) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #125))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #118))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #115) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #119) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #122)) #("\n" 0 1 (:parent #122))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #119) #(" " 0 2 (:parent #123)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #123) #("NAR (Nix Archive Format)" 0 24 (:parent #127))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #123)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #123) #("hello" 0 5 (:parent #129))) #("package.\n" 0 9 (:parent #123))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #119) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #124))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #119)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #119)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #119) #(" The result is composed of a few parts:\n" 0 41 (:parent #127))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #119) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #131))) :mode item :granularity nil :parent #128) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #131) #("the guix store path\n" 0 20 (:parent #134)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #132))) :mode item :granularity nil :parent #128) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #132) #("a hash uniquely identifying the store item\n" 0 43 (:parent #135)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #133))) :mode item :granularity nil :parent #128) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #133) #("the package-name and version, separated by dashes\n" 0 50 (:parent #136))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #119) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #129)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #129)) #(".\n" 0 2 (:parent #129))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #119))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #115) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #120) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #123)) #("\n" 0 1 (:parent #123))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #120) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #124)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #124)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #124)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #124)) #("file.\n" 0 6 (:parent #124))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #120)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #120)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #120) #(" If the package is not available, this would return a " 0 55 (:parent #127)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #127)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #127)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #127)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #127)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #127)) #("below.\n" 0 7 (:parent #127))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #120) #(" #+begin" 0 9 (:parent #128)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #128) #("src" 0 3 (:parent #132))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #128)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #128) #("nar" 0 3 (:parent #134))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #128)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #128) #("pass" 0 4 (:parent #136))) #("\" url \";\")\n \"client" 0 25 (:parent #128)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #128) #("body" 0 4 (:parent #138))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #128) #("buffer" 0 6 (:parent #139))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #128) #("size" 0 4 (:parent #140))) #("256k;\"\n" 0 7 (:parent #128)))))))))) . #0)) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #3) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #6) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #9)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #9)) #("field of our " 0 13 (:parent #9)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #9)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #9))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #6))))) "")
org-export-data((headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #0))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #46))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #92) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #95)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #95)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #95) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #108))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #95) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #109))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #95) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #110))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #95) #("Earlier this year " 0 18 (:parent #111)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #111) #("I announced on the guix mailing list" 0 36 (:parent #115))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #111)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #96))) :mode nil :granularity nil :parent #92) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #96) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #99) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #102))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #99) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #103) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #106) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #109) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #112) #("Improved Build Diversity" 0 24 (:parent #115)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #109)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #103) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #107) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #110) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #113) #("Reduced Latency" 0 15 (:parent #116)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #110)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #103) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #108) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #111) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #114) #("Increased Resilience" 0 20 (:parent #117)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #111)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #103) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #109) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #112) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #115) #("Community Contribution" 0 22 (:parent #118)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #112))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #99) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #104)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #104) #("here" 0 4 (:parent #108))) #(".\n" 0 2 (:parent #104))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #97))) :mode nil :granularity nil :parent #92) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #97) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #100) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #103))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #100) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #107) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #110) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #113) #("Processor" 0 9 (:parent #116)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #110)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #108) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #111) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #114) #("RAM" 0 3 (:parent #117)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #111)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #109) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #112) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #115) #("Storage" 0 7 (:parent #118)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #112)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #110) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #113) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #116) #("Network" 0 7 (:parent #119)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #113)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #111) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #114) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #117) #("Location" 0 8 (:parent #120)))) #(": Memphis TN\n" 0 13 (:parent #114))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #100) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #105))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #100) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #106))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #100) #("For more details, see the " 0 26 (:parent #107)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #107) #("Specifications section" 0 22 (:parent #111))) #("of the Cuirass Manual.\n" 0 23 (:parent #107))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #100) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #108))))) #46)) #0 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #50))) :mode nil :granularity nil :parent #46) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #50) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #53) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #56)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #56) #("guix publish" 0 12 (:parent #60))) #(", which Guix provides the " 0 26 (:parent #56)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #56) #("guix-publish-service-type" 0 25 (:parent #62))) #(",\nwhich is used in the " 0 23 (:parent #56)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #56)) #("field of " 0 9 (:parent #56)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #56)) #("definition.\n" 0 12 (:parent #56))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #53)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #53) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #58))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #51))) :mode nil :granularity nil :parent #46) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #51) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #54) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #57))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #54) #("To anonymize nginx access logs, the " 0 36 (:parent #58)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #58) #("anonip-service-type" 0 19 (:parent #62))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #58)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #58)) #("is defined.\n" 0 12 (:parent #58))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #54)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #54) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #60))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #54)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #54) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #62)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #62)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #62))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #54)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #54) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #64)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #64)) #("field of our\n" 0 13 (:parent #64)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #64)) #("declaration.\n" 0 13 (:parent #64))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #54)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #52))) :mode nil :granularity nil :parent #46) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #52) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #55) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #58)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #56))) :mode nil :granularity nil :parent #52) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #56) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #59) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #62)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #62) #("letsencrypt" 0 11 (:parent #66))) #("via the " 0 8 (:parent #62)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #62) #("certbot" 0 7 (:parent #68))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #62)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #62) #("certbox-service-type" 0 20 (:parent #70))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #62)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #62)) #("field in our " 0 13 (:parent #62)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #62)) #("configuration.\n" 0 15 (:parent #62))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #59)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #59) #("This service references " 0 24 (:parent #64)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #64)) #(", which we define below. It sends " 0 34 (:parent #64)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #64)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #64))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #59)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #59) #("Next we define a function we will use later in the " 0 51 (:parent #66)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #66) #("Configure Nginx Server Blocks" 0 29 (:parent #70))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #66))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #59)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #57)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #57))) :mode nil :granularity nil :parent #52) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #57) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #60) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #63))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #60)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #60) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #65))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #60) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #66) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #69) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #72)) #("\n" 0 1 (:parent #72))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #69) #(" " 0 2 (:parent #73)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #73)) #("provides a route " 0 17 (:parent #73)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #73)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #73)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #73)) #("command). Given away by the reference to " 0 41 (:parent #73)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #73) #("Nix" 0 3 (:parent #83))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #73)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #73) #("Nix Binary Cache" 0 16 (:parent #85))) #(".\n" 0 2 (:parent #73))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #69) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #74))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #69)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #69) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #76))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #69))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #66) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #70) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #73)) #("\n" 0 1 (:parent #73))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #70) #(" " 0 2 (:parent #74)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #74) #("NAR (Nix Archive Format)" 0 24 (:parent #78))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #74)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #74) #("hello" 0 5 (:parent #80))) #("package.\n" 0 9 (:parent #74))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #70) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #75))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #70)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #70)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #70) #(" The result is composed of a few parts:\n" 0 41 (:parent #78))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #70) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #82))) :mode item :granularity nil :parent #79) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #82) #("the guix store path\n" 0 20 (:parent #85)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #83))) :mode item :granularity nil :parent #79) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #83) #("a hash uniquely identifying the store item\n" 0 43 (:parent #86)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #84))) :mode item :granularity nil :parent #79) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #84) #("the package-name and version, separated by dashes\n" 0 50 (:parent #87))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #70) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #80)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #80)) #(".\n" 0 2 (:parent #80))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #70))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #66) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #71) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #74)) #("\n" 0 1 (:parent #74))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #71) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #75)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #75)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #75)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #75)) #("file.\n" 0 6 (:parent #75))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #71)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #71)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #71) #(" If the package is not available, this would return a " 0 55 (:parent #78)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #78)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #78)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #78)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #78)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #78)) #("below.\n" 0 7 (:parent #78))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #71) #(" #+begin" 0 9 (:parent #79)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #79) #("src" 0 3 (:parent #83))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #79)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #79) #("nar" 0 3 (:parent #85))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #79)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #79) #("pass" 0 4 (:parent #87))) #("\" url \";\")\n \"client" 0 25 (:parent #79)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #79) #("body" 0 4 (:parent #89))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #79) #("buffer" 0 6 (:parent #90))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #79) #("size" 0 4 (:parent #91))) #("256k;\"\n" 0 7 (:parent #79)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #0) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #3) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #6)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #6) #("Guix channels" 0 13 (:parent #10))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #6)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #4))) :mode nil :granularity nil :parent #0) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #4) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #7) #("In order to run Cuirass via the " 0 32 (:parent #10)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #10)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #10)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #10)) #("as a " 0 5 (:parent #10)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #10) #("G-Expression" 0 12 (:parent #18))) #("that will return a list of\n" 0 27 (:parent #10)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #10) #("cuirass specifications" 0 22 (:parent #20))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #10))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #7)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #7) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #12)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #12)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #12)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #12) #("Cuirass specification" 0 21 (:parent #18))) #("\ndocumentation for more details.\n" 0 33 (:parent #12))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #7) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #13)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #13) #("Guix Configuration as a Channel" 0 31 (:parent #17))) #(".\n" 0 2 (:parent #13))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #5))) :mode nil :granularity nil :parent #0) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #5) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #8) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #11)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #11)) #("field of our " 0 13 (:parent #11)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #11)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #11))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #8))))) (:export-options (body-only) :back-end #s(org-export-backend :name html :parent nil :transcoders ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :options ((:html-doctype "HTML_DOCTYPE" nil org-html-doctype) (:html-container "HTML_CONTAINER" nil org-html-container-element) (:html-content-class "HTML_CONTENT_CLASS" nil org-html-content-class) (:description "DESCRIPTION" nil nil newline) (:keywords "KEYWORDS" nil nil space) (:html-html5-fancy nil "html5-fancy" org-html-html5-fancy) (:html-link-use-abs-url nil "html-link-use-abs-url" org-html-link-use-abs-url) (:html-link-home "HTML_LINK_HOME" nil org-html-link-home) (:html-link-up "HTML_LINK_UP" nil org-html-link-up) (:html-mathjax "HTML_MATHJAX" nil "" space) (:html-equation-reference-format "HTML_EQUATION_REFERENCE_FORMAT" nil org-html-equation-reference-format t) (:html-postamble nil "html-postamble" org-html-postamble) (:html-preamble nil "html-preamble" org-html-preamble) (:html-head "HTML_HEAD" nil org-html-head newline) (:html-head-extra "HTML_HEAD_EXTRA" nil org-html-head-extra newline) (:subtitle "SUBTITLE" nil nil parse) (:html-head-include-default-style nil "html-style" org-html-head-include-default-style) (:html-head-include-scripts nil "html-scripts" org-html-head-include-scripts) (:html-allow-name-attribute-in-anchors nil nil org-html-allow-name-attribute-in-anchors) (:html-divs nil nil org-html-divs) (:html-checkbox-type nil nil org-html-checkbox-type) (:html-extension nil nil org-html-extension) (:html-footnote-format nil nil org-html-footnote-format) (:html-footnote-separator nil nil org-html-footnote-separator) (:html-footnotes-section nil nil org-html-footnotes-section) (:html-format-drawer-function nil nil org-html-format-drawer-function) (:html-format-headline-function nil nil org-html-format-headline-function) (:html-format-inlinetask-function nil nil org-html-format-inlinetask-function) (:html-home/up-format nil nil org-html-home/up-format) (:html-indent nil nil org-html-indent) (:html-infojs-options nil nil org-html-infojs-options) (:html-infojs-template nil nil org-html-infojs-template) (:html-inline-image-rules nil nil org-html-inline-image-rules) (:html-link-org-files-as-html nil nil org-html-link-org-files-as-html) (:html-mathjax-options nil nil org-html-mathjax-options) (:html-mathjax-template nil nil org-html-mathjax-template) (:html-metadata-timestamp-format nil nil org-html-metadata-timestamp-format) (:html-postamble-format nil nil org-html-postamble-format) (:html-preamble-format nil nil org-html-preamble-format) (:html-prefer-user-labels nil nil org-html-prefer-user-labels) (:html-self-link-headlines nil nil org-html-self-link-headlines) (:html-table-align-individual-fields nil nil org-html-table-align-individual-fields) (:html-table-caption-above nil nil org-html-table-caption-above) (:html-table-data-tags nil nil org-html-table-data-tags) (:html-table-header-tags nil nil org-html-table-header-tags) (:html-table-use-header-tags-for-first-column nil nil org-html-table-use-header-tags-for-first-column) (:html-tag-class-prefix nil nil org-html-tag-class-prefix) (:html-text-markup-alist nil nil org-html-text-markup-alist) (:html-todo-kwd-class-prefix nil nil org-html-todo-kwd-class-prefix) (:html-toplevel-hlevel nil nil org-html-toplevel-hlevel) (:html-use-infojs nil nil org-html-use-infojs) (:html-validation-link nil nil org-html-validation-link) (:html-viewport nil nil org-html-viewport) (:html-inline-images nil nil org-html-inline-images) (:html-table-attributes nil nil org-html-table-default-attributes) (:html-table-row-open-tag nil nil org-html-table-row-open-tag) (:html-table-row-close-tag nil nil org-html-table-row-close-tag) (:html-xml-declaration nil nil org-html-xml-declaration) (:html-wrap-src-lines nil nil org-html-wrap-src-lines) (:html-klipsify-src nil nil org-html-klipsify-src) (:html-klipse-css nil nil org-html-klipse-css) (:html-klipse-js nil nil org-html-klipse-js) (:html-klipse-selection-script nil nil org-html-klipse-selection-script) (:infojs-opt "INFOJS_OPT" nil nil) (:creator "CREATOR" nil org-html-creator-string) (:with-latex nil "tex" org-html-with-latex) (:latex-header "LATEX_HEADER" nil nil newline)) :filters ((:filter-options . org-html-infojs-install-script) (:filter-parse-tree . org-html-image-link-filter) (:filter-final-output . org-html-final-function)) :blocks nil :menu (104 "Export to HTML" ((72 "As HTML buffer" org-html-export-as-html) (104 "As HTML file" org-html-export-to-html) (111 "As HTML file and open" (lambda (a s v b) (if a (org-html-export-to-html t s v b) (org-open-file (org-html-export-to-html nil s v b)))))))) :translate-alist ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data # :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil :html-divs ((preamble "div" "preamble") (content "div" "content") (postamble "div" "postamble")) :html-checkbox-type ascii :html-extension "html" :html-footnote-format "%s" :html-footnote-separator ", " :html-footnotes-section ") :html-format-headline-function org-html-format-headline-default-function :html-format-inlinetask-function org-html-format-inlinetask-default-function :html-home/up-format "" :html-indent nil :html-infojs-options ((path . "https://orgmode.org/org-info.js") (view . "info") (toc . :with-toc) (ftoc . "0") (tdepth . "max") (sdepth . "max") (mouse . "underline") (buttons . "0") (ltoc . "1") (up . :html-link-up) (home . :html-link-home)) :html-infojs-template "\n\n" :html-inline-image-rules (("file" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("http" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("https" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)")) :html-link-org-files-as-html t :html-mathjax-options ((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js") (scale 1.0) (align "center") (font "mathjax-modern") (overflow "overflow") (tags "ams") (indent "0em") (multlinewidth "85%") (tagindent ".8em") (tagside "right")) :html-mathjax-template "\n\n" :html-metadata-timestamp-format "%Y-%m-%d %a %H:%M" :html-postamble-format (("en" " \n" . " ") :html-table-header-tags ("" . " ") :html-table-use-header-tags-for-first-column nil :html-tag-class-prefix "" :html-text-markup-alist ((bold . "%s") (code . "%s") (underline . "%s") (verbatim . "" :html-table-row-close-tag " " :html-xml-declaration (("html" . "") ("php" . "\"; ?>")) :html-wrap-src-lines nil :html-klipsify-src nil :html-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css" :html-klipse-js "https://storage.googleapis.com/app.klipse.tech/plugin_prod/js/klipse_plugin.min.js" :html-klipse-selection-script "window.klipse_settings = {selector_eval_html: '.src-html',\n selector_eval_js: '.src-js',\n selector_eval_python_client: '.src-python',\n selector_eval_scheme: '.src-scheme',\n selector: '.src-clojure',\n selector_eval_ruby: '.src-ruby'};" :infojs-opt nil :creator "Emacs 29.4 (Org mode 9.6.15)" :with-latex t :latex-header "\\usepackage[margin=1.5cm]{geometry}\n\\usepackage{xcolor}\n\\definecolor{link}{HTML}{506060}\n\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :title (#("Setup of a Simple Guix Build Farm and Substitute Server" 0 55 (:parent #148))) :date nil :author (#("Collin J. Doering" 0 17 (:parent #152))) :email "unknown@genenetwork-development" :language "en" :select-tags ("export") :exclude-tags ("noexport") :headline-levels 3 :preserve-breaks nil :section-numbers nil :time-stamp-file t :with-archived-trees headline :with-author t :with-broken-links nil :with-clocks nil :with-creator nil :with-date t :with-drawers (not "LOGBOOK") :with-email nil :with-emphasize t :with-entities t :with-fixed-width t :with-footnotes t :with-inlinetasks t :with-planning nil :with-priority nil :with-properties nil :with-smart-quotes nil :with-special-strings t :with-statistics-cookies t :with-sub-superscript t :with-toc nil :with-tables t :with-tags t :with-tasks t :with-timestamps t :with-title t :with-todo-keywords t :cite-export (basic nil nil) :bibliography nil :filter-body nil :filter-bold nil :filter-babel-call nil :filter-center-block nil :filter-clock nil :filter-code nil :filter-diary-sexp nil :filter-drawer nil :filter-dynamic-block nil :filter-entity nil :filter-example-block nil :filter-export-block nil :filter-export-snippet nil :filter-final-output (org-html-final-function) :filter-fixed-width nil :filter-footnote-definition nil :filter-footnote-reference nil :filter-headline nil :filter-horizontal-rule nil :filter-inline-babel-call nil :filter-inline-src-block nil :filter-inlinetask nil :filter-italic nil :filter-item nil :filter-keyword nil :filter-latex-environment nil :filter-latex-fragment nil :filter-line-break nil :filter-link nil :filter-node-property nil :filter-options (org-html-infojs-install-script) :filter-paragraph nil :filter-parse-tree (org-html-image-link-filter) :filter-plain-list nil :filter-plain-text nil :filter-planning nil :filter-property-drawer nil :filter-quote-block nil :filter-radio-target nil :filter-section nil :filter-special-block nil :filter-src-block nil :filter-statistics-cookie nil :filter-strike-through nil :filter-subscript nil :filter-superscript nil :filter-table nil :filter-table-cell nil :filter-table-row nil :filter-target nil :filter-timestamp nil :filter-underline nil :filter-verbatim nil :filter-verse-block nil :ignore-list nil :parse-tree (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #338) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #341)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #341)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #341) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #354))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #341) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #355))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #341) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #356))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #341) #("Earlier this year " 0 18 (:parent #357)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #357) #("I announced on the guix mailing list" 0 36 (:parent #361))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #357)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #342))) :mode nil :granularity nil :parent #338) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #342) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #345) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #348))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #345) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #352) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #355) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #358) #("Improved Build Diversity" 0 24 (:parent #361)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #355)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #353) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #356) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #359) #("Reduced Latency" 0 15 (:parent #362)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #356)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #354) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #357) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #360) #("Increased Resilience" 0 20 (:parent #363)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #357)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #355) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #358) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #361) #("Community Contribution" 0 22 (:parent #364)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #358))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #345) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #350)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #350) #("here" 0 4 (:parent #354))) #(".\n" 0 2 (:parent #350))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #343))) :mode nil :granularity nil :parent #338) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #343) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #346) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #349))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #346) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #353) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #356) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #359) #("Processor" 0 9 (:parent #362)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #356)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #354) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #357) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #360) #("RAM" 0 3 (:parent #363)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #357)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #355) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #358) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #361) #("Storage" 0 7 (:parent #364)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #358)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #356) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #359) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #362) #("Network" 0 7 (:parent #365)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #359)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #357) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #360) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #363) #("Location" 0 8 (:parent #366)))) #(": Memphis TN\n" 0 13 (:parent #360))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #346) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #351))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #346) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #352))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #346) #("For more details, see the " 0 26 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #353) #("Specifications section" 0 22 (:parent #357))) #("of the Cuirass Manual.\n" 0 23 (:parent #353))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #346) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #354))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #344))) :mode nil :granularity nil :parent #338) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #347))) :mode section :granularity nil :parent #344) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #347) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #350) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #353) #("Guix channels" 0 13 (:parent #357))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #353)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #351))) :mode nil :granularity nil :parent #347) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #351) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #354) #("In order to run Cuirass via the " 0 32 (:parent #357)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #357)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #357)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #357)) #("as a " 0 5 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #357) #("G-Expression" 0 12 (:parent #365))) #("that will return a list of\n" 0 27 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #357) #("cuirass specifications" 0 22 (:parent #367))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #357))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #354)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #354) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #359)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #359)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #359)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #359) #("Cuirass specification" 0 21 (:parent #365))) #("\ndocumentation for more details.\n" 0 33 (:parent #359))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #354) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #360)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #360) #("Guix Configuration as a Channel" 0 31 (:parent #364))) #(".\n" 0 2 (:parent #360))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #352))) :mode nil :granularity nil :parent #347) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #352) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #355) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #358)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #358)) #("field of our " 0 13 (:parent #358)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #358)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #355))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #348))) :mode nil :granularity nil :parent #344) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #348) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #351) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #354)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #354) #("guix publish" 0 12 (:parent #358))) #(", which Guix provides the " 0 26 (:parent #354)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #354) #("guix-publish-service-type" 0 25 (:parent #360))) #(",\nwhich is used in the " 0 23 (:parent #354)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #354)) #("field of " 0 9 (:parent #354)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #354)) #("definition.\n" 0 12 (:parent #354))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #351)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #351) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #356))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #349))) :mode nil :granularity nil :parent #344) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #349) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #352) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #355))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #352) #("To anonymize nginx access logs, the " 0 36 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #356) #("anonip-service-type" 0 19 (:parent #360))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #356)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #356)) #("is defined.\n" 0 12 (:parent #356))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #352) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #352) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #360)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #360)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #352)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #352) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #362)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #362)) #("field of our\n" 0 13 (:parent #362)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #362)) #("declaration.\n" 0 13 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #352)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #350))) :mode nil :granularity nil :parent #344) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #350) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #353) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #356)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #354) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #357) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #360)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #360) #("letsencrypt" 0 11 (:parent #364))) #("via the " 0 8 (:parent #360)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #360) #("certbot" 0 7 (:parent #366))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #360) #("certbox-service-type" 0 20 (:parent #368))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #360)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #360)) #("field in our " 0 13 (:parent #360)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #360)) #("configuration.\n" 0 15 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #357) #("This service references " 0 24 (:parent #362)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #362)) #(", which we define below. It sends " 0 34 (:parent #362)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #362)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #357) #("Next we define a function we will use later in the " 0 51 (:parent #364)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #364) #("Configure Nginx Server Blocks" 0 29 (:parent #368))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #364))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #357)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #355)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #355) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #358) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #358)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #358) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #363))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #358) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #367) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #370)) #("\n" 0 1 (:parent #370))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #367) #(" " 0 2 (:parent #371)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #371)) #("provides a route " 0 17 (:parent #371)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #371)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #371)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #371)) #("command). Given away by the reference to " 0 41 (:parent #371)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #371) #("Nix" 0 3 (:parent #381))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #371)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #371) #("Nix Binary Cache" 0 16 (:parent #383))) #(".\n" 0 2 (:parent #371))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #367) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #372))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #367)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #367) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #374))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #367))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #368) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #371)) #("\n" 0 1 (:parent #371))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #368) #(" " 0 2 (:parent #372)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #372) #("NAR (Nix Archive Format)" 0 24 (:parent #376))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #372)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #372) #("hello" 0 5 (:parent #378))) #("package.\n" 0 9 (:parent #372))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #368) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #368)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #368)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #368) #(" The result is composed of a few parts:\n" 0 41 (:parent #376))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #368) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #380))) :mode item :granularity nil :parent #377) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #380) #("the guix store path\n" 0 20 (:parent #383)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #381))) :mode item :granularity nil :parent #377) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #381) #("a hash uniquely identifying the store item\n" 0 43 (:parent #384)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #382))) :mode item :granularity nil :parent #377) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #382) #("the package-name and version, separated by dashes\n" 0 50 (:parent #385))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #368) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #378)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #378)) #(".\n" 0 2 (:parent #378))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #368))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #369) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #372)) #("\n" 0 1 (:parent #372))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #369) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #373)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #373)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #373)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #373)) #("file.\n" 0 6 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #369)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #369)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #369) #(" If the package is not available, this would return a " 0 55 (:parent #376)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #376)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #376)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #376)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #376)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #376)) #("below.\n" 0 7 (:parent #376))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #369) #(" #+begin" 0 9 (:parent #377)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #377) #("src" 0 3 (:parent #381))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #377)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #377) #("nar" 0 3 (:parent #383))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #377)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #377) #("pass" 0 4 (:parent #385))) #("\" url \";\")\n \"client" 0 25 (:parent #377)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #377) #("body" 0 4 (:parent #387))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #377) #("buffer" 0 6 (:parent #388))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #377) #("size" 0 4 (:parent #389))) #("256k;\"\n" 0 7 (:parent #377)))))))))) :headline-offset 0 :headline-numbering nil :id-alist nil :citations nil :internal-references (("org1d65611" headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #350))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #396))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #442) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #445)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #445)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #445) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #458))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #445) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #459))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #445) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #460))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #445) #("Earlier this year " 0 18 (:parent #461)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #461) #("I announced on the guix mailing list" 0 36 (:parent #465))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #461)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #446))) :mode nil :granularity nil :parent #442) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #446) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #449) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #452))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #449) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #456) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #459) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #462) #("Improved Build Diversity" 0 24 (:parent #465)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #459)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #457) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #460) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #463) #("Reduced Latency" 0 15 (:parent #466)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #460)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #458) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #461) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #464) #("Increased Resilience" 0 20 (:parent #467)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #461)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #459) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #462) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #465) #("Community Contribution" 0 22 (:parent #468)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #462))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #449) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #454)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #454) #("here" 0 4 (:parent #458))) #(".\n" 0 2 (:parent #454))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #447))) :mode nil :granularity nil :parent #442) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #447) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #450) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #453))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #450) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #457) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #460) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #463) #("Processor" 0 9 (:parent #466)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #460)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #458) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #461) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #464) #("RAM" 0 3 (:parent #467)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #461)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #459) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #462) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #465) #("Storage" 0 7 (:parent #468)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #462)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #460) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #463) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #466) #("Network" 0 7 (:parent #469)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #463)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #461) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #464) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #467) #("Location" 0 8 (:parent #470)))) #(": Memphis TN\n" 0 13 (:parent #464))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #450) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #455))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #450) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #456))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #450) #("For more details, see the " 0 26 (:parent #457)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #457) #("Specifications section" 0 22 (:parent #461))) #("of the Cuirass Manual.\n" 0 23 (:parent #457))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #450) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #458))))) #396)) #350 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #400))) :mode nil :granularity nil :parent #396) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #400) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #403) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #406)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #406) #("guix publish" 0 12 (:parent #410))) #(", which Guix provides the " 0 26 (:parent #406)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #406) #("guix-publish-service-type" 0 25 (:parent #412))) #(",\nwhich is used in the " 0 23 (:parent #406)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #406)) #("field of " 0 9 (:parent #406)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #406)) #("definition.\n" 0 12 (:parent #406))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #403)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #403) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #408))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #401))) :mode nil :granularity nil :parent #396) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #401) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #404) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #407))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #404) #("To anonymize nginx access logs, the " 0 36 (:parent #408)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #408) #("anonip-service-type" 0 19 (:parent #412))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #408)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #408)) #("is defined.\n" 0 12 (:parent #408))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #404) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #410))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #404) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #412)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #412)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #404)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #404) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #414)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #414)) #("field of our\n" 0 13 (:parent #414)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #414)) #("declaration.\n" 0 13 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #404)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #402))) :mode nil :granularity nil :parent #396) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #402) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #405) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #408)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #406))) :mode nil :granularity nil :parent #402) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #406) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #409) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #412)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #412) #("letsencrypt" 0 11 (:parent #416))) #("via the " 0 8 (:parent #412)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #412) #("certbot" 0 7 (:parent #418))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #412)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #412) #("certbox-service-type" 0 20 (:parent #420))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #412)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #412)) #("field in our " 0 13 (:parent #412)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #412)) #("configuration.\n" 0 15 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #409) #("This service references " 0 24 (:parent #414)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #414)) #(", which we define below. It sends " 0 34 (:parent #414)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #414)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #409) #("Next we define a function we will use later in the " 0 51 (:parent #416)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #416) #("Configure Nginx Server Blocks" 0 29 (:parent #420))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #416))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #409)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #407)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #407) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #410) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #413))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #410)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #410) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #415))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #419) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #422)) #("\n" 0 1 (:parent #422))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #419) #(" " 0 2 (:parent #423)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #423)) #("provides a route " 0 17 (:parent #423)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #423)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #423)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #423)) #("command). Given away by the reference to " 0 41 (:parent #423)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #423) #("Nix" 0 3 (:parent #433))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #423)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #423) #("Nix Binary Cache" 0 16 (:parent #435))) #(".\n" 0 2 (:parent #423))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #419) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #424))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #419)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #419) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #419))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #420) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #423)) #("\n" 0 1 (:parent #423))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #420) #(" " 0 2 (:parent #424)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #424) #("NAR (Nix Archive Format)" 0 24 (:parent #428))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #424)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #424) #("hello" 0 5 (:parent #430))) #("package.\n" 0 9 (:parent #424))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #420) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #420)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #420)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #420) #(" The result is composed of a few parts:\n" 0 41 (:parent #428))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #420) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #432))) :mode item :granularity nil :parent #429) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #432) #("the guix store path\n" 0 20 (:parent #435)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #433))) :mode item :granularity nil :parent #429) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #433) #("a hash uniquely identifying the store item\n" 0 43 (:parent #436)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #434))) :mode item :granularity nil :parent #429) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #434) #("the package-name and version, separated by dashes\n" 0 50 (:parent #437))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #420) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #430)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #430)) #(".\n" 0 2 (:parent #430))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #420))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #421) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #424)) #("\n" 0 1 (:parent #424))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #421) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #425)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #425)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #425)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #425)) #("file.\n" 0 6 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #421)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #421)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #421) #(" If the package is not available, this would return a " 0 55 (:parent #428)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #428)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #428)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #428)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #428)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #428)) #("below.\n" 0 7 (:parent #428))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #421) #(" #+begin" 0 9 (:parent #429)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #429) #("src" 0 3 (:parent #433))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #429)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #429) #("nar" 0 3 (:parent #435))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #429)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #429) #("pass" 0 4 (:parent #437))) #("\" url \";\")\n \"client" 0 25 (:parent #429)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #429) #("body" 0 4 (:parent #439))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #429) #("buffer" 0 6 (:parent #440))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #429) #("size" 0 4 (:parent #441))) #("256k;\"\n" 0 7 (:parent #429)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #350) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #353) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #356) #("Guix channels" 0 13 (:parent #360))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #356)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #354) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #357) #("In order to run Cuirass via the " 0 32 (:parent #360)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #360)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #360)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #360)) #("as a " 0 5 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #360) #("G-Expression" 0 12 (:parent #368))) #("that will return a list of\n" 0 27 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #360) #("cuirass specifications" 0 22 (:parent #370))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #357)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #357) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #362)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #362)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #362)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #362) #("Cuirass specification" 0 21 (:parent #368))) #("\ndocumentation for more details.\n" 0 33 (:parent #362))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #357) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #363)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #363) #("Guix Configuration as a Channel" 0 31 (:parent #367))) #(".\n" 0 2 (:parent #363))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #355) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #358) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #361)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #361)) #("field of our " 0 13 (:parent #361)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #361)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #358))))) ((other "Cuirass" "-" "Building" "Packages") . 30823953) ((headline "Cuirass" "-" "Building" "Packages") . 30823953) ("org46b8c57" headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #353))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #399) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #402)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #402)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #402) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #415))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #402) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #416))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #402) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #417))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #402) #("Earlier this year " 0 18 (:parent #418)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #418) #("I announced on the guix mailing list" 0 36 (:parent #422))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #418)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #403))) :mode nil :granularity nil :parent #399) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #403) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #406) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #409))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #406) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #413) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #416) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #419) #("Improved Build Diversity" 0 24 (:parent #422)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #416)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #414) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #417) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #420) #("Reduced Latency" 0 15 (:parent #423)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #417)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #415) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #418) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #421) #("Increased Resilience" 0 20 (:parent #424)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #418)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #416) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #419) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #422) #("Community Contribution" 0 22 (:parent #425)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #419))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #406) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #411)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #411) #("here" 0 4 (:parent #415))) #(".\n" 0 2 (:parent #411))))) #353 (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #405))) :mode nil :granularity nil :parent #399) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #408))) :mode section :granularity nil :parent #405) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #408) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #411) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #414)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #414) #("Guix channels" 0 13 (:parent #418))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #414)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #412) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #415) #("In order to run Cuirass via the " 0 32 (:parent #418)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #418)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #418)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #418)) #("as a " 0 5 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #418) #("G-Expression" 0 12 (:parent #426))) #("that will return a list of\n" 0 27 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #418) #("cuirass specifications" 0 22 (:parent #428))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #415)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #415) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #420)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #420)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #420) #("Cuirass specification" 0 21 (:parent #426))) #("\ndocumentation for more details.\n" 0 33 (:parent #420))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #415) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #421)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #421) #("Guix Configuration as a Channel" 0 31 (:parent #425))) #(".\n" 0 2 (:parent #421))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #413) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #416) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #419)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #419)) #("field of our " 0 13 (:parent #419)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #419)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #416))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #409))) :mode nil :granularity nil :parent #405) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #409) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #412) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #415)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #415) #("guix publish" 0 12 (:parent #419))) #(", which Guix provides the " 0 26 (:parent #415)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #415) #("guix-publish-service-type" 0 25 (:parent #421))) #(",\nwhich is used in the " 0 23 (:parent #415)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #415)) #("field of " 0 9 (:parent #415)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #415)) #("definition.\n" 0 12 (:parent #415))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #412)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #412) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #417))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #410))) :mode nil :granularity nil :parent #405) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #410) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #413) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #416))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #413) #("To anonymize nginx access logs, the " 0 36 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #417) #("anonip-service-type" 0 19 (:parent #421))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #417)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #417)) #("is defined.\n" 0 12 (:parent #417))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #413) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #413) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #421)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #421)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #413)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #413) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #423)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #423)) #("field of our\n" 0 13 (:parent #423)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #423)) #("declaration.\n" 0 13 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #413)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #411))) :mode nil :granularity nil :parent #405) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #411) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #414) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #417)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #415) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #418) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #421)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #421) #("letsencrypt" 0 11 (:parent #425))) #("via the " 0 8 (:parent #421)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #421) #("certbot" 0 7 (:parent #427))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #421) #("certbox-service-type" 0 20 (:parent #429))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #421)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #421)) #("field in our " 0 13 (:parent #421)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #421)) #("configuration.\n" 0 15 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #418) #("This service references " 0 24 (:parent #423)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #423)) #(", which we define below. It sends " 0 34 (:parent #423)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #423)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #418) #("Next we define a function we will use later in the " 0 51 (:parent #425)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #425) #("Configure Nginx Server Blocks" 0 29 (:parent #429))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #418)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #416)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #416) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #419) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #419)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #419) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #424))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #419) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #428) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #431)) #("\n" 0 1 (:parent #431))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #428) #(" " 0 2 (:parent #432)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #432)) #("provides a route " 0 17 (:parent #432)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #432)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #432)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #432)) #("command). Given away by the reference to " 0 41 (:parent #432)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #432) #("Nix" 0 3 (:parent #442))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #432)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #432) #("Nix Binary Cache" 0 16 (:parent #444))) #(".\n" 0 2 (:parent #432))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #428) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #433))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #428)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #428) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #435))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #428))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #429) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #432)) #("\n" 0 1 (:parent #432))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #429) #(" " 0 2 (:parent #433)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #433) #("NAR (Nix Archive Format)" 0 24 (:parent #437))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #433)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #433) #("hello" 0 5 (:parent #439))) #("package.\n" 0 9 (:parent #433))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #429) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #429)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #429)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #429) #(" The result is composed of a few parts:\n" 0 41 (:parent #437))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #429) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #441))) :mode item :granularity nil :parent #438) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #441) #("the guix store path\n" 0 20 (:parent #444)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #442))) :mode item :granularity nil :parent #438) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #442) #("a hash uniquely identifying the store item\n" 0 43 (:parent #445)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #443))) :mode item :granularity nil :parent #438) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #443) #("the package-name and version, separated by dashes\n" 0 50 (:parent #446))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #429) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #439)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #439)) #(".\n" 0 2 (:parent #439))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #429))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #430) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #433)) #("\n" 0 1 (:parent #433))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #430) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #434)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #434)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #434)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #434)) #("file.\n" 0 6 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #430)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #430)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #430) #(" If the package is not available, this would return a " 0 55 (:parent #437)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #437)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #437)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #437)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #437)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #437)) #("below.\n" 0 7 (:parent #437))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #430) #(" #+begin" 0 9 (:parent #438)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #438) #("src" 0 3 (:parent #442))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #438)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #438) #("nar" 0 3 (:parent #444))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #438)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #438) #("pass" 0 4 (:parent #446))) #("\" url \";\")\n \"client" 0 25 (:parent #438)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #438) #("body" 0 4 (:parent #448))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #438) #("buffer" 0 6 (:parent #449))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #438) #("size" 0 4 (:parent #450))) #("256k;\"\n" 0 7 (:parent #438))))))))))) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #353) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #356) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #359))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #356) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #363) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #366) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #369) #("Processor" 0 9 (:parent #372)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #366)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #364) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #367) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #370) #("RAM" 0 3 (:parent #373)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #367)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #365) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #368) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #371) #("Storage" 0 7 (:parent #374)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #368)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #366) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #369) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #372) #("Network" 0 7 (:parent #375)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #369)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #367) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #370) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #373) #("Location" 0 8 (:parent #376)))) #(": Memphis TN\n" 0 13 (:parent #370))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #356) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #361))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #356) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #362))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #356) #("For more details, see the " 0 26 (:parent #363)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #363) #("Specifications section" 0 22 (:parent #367))) #("of the Cuirass Manual.\n" 0 23 (:parent #363))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #356) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #364))))) ((other "Hardware" "and" "Infrastructure") . 74157143) ((headline "Hardware" "and" "Infrastructure") . 74157143) ("orgcc40a3d" headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #356))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #402) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #405)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #405)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #405) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #418))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #405) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #419))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #405) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #420))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #405) #("Earlier this year " 0 18 (:parent #421)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #421) #("I announced on the guix mailing list" 0 36 (:parent #425))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #421)))) #356 (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #407) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #410) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #413))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #417) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #420) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #423) #("Processor" 0 9 (:parent #426)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #420)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #418) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #421) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #424) #("RAM" 0 3 (:parent #427)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #421)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #419) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #422) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #425) #("Storage" 0 7 (:parent #428)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #422)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #420) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #423) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #426) #("Network" 0 7 (:parent #429)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #423)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #421) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #424) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #427) #("Location" 0 8 (:parent #430)))) #(": Memphis TN\n" 0 13 (:parent #424))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #410) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #415))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #410) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #416))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #410) #("For more details, see the " 0 26 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #417) #("Specifications section" 0 22 (:parent #421))) #("of the Cuirass Manual.\n" 0 23 (:parent #417))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #410) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #418))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #408))) :mode nil :granularity nil :parent #402) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #411))) :mode section :granularity nil :parent #408) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #411) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #414) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #417) #("Guix channels" 0 13 (:parent #421))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #417)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #415) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #418) #("In order to run Cuirass via the " 0 32 (:parent #421)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #421)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #421)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #421)) #("as a " 0 5 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #421) #("G-Expression" 0 12 (:parent #429))) #("that will return a list of\n" 0 27 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #421) #("cuirass specifications" 0 22 (:parent #431))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #418)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #418) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #423)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #423)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #423)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #423) #("Cuirass specification" 0 21 (:parent #429))) #("\ndocumentation for more details.\n" 0 33 (:parent #423))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #418) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #424)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #424) #("Guix Configuration as a Channel" 0 31 (:parent #428))) #(".\n" 0 2 (:parent #424))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #416) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #419) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #422)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #422)) #("field of our " 0 13 (:parent #422)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #422)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #419))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #412) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #415) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #418) #("guix publish" 0 12 (:parent #422))) #(", which Guix provides the " 0 26 (:parent #418)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #418) #("guix-publish-service-type" 0 25 (:parent #424))) #(",\nwhich is used in the " 0 23 (:parent #418)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #418)) #("field of " 0 9 (:parent #418)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #418)) #("definition.\n" 0 12 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #415)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #415) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #420))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #413) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #416) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #419))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #416) #("To anonymize nginx access logs, the " 0 36 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #420) #("anonip-service-type" 0 19 (:parent #424))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #420)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #420)) #("is defined.\n" 0 12 (:parent #420))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #416) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #416) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #424)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #424)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #416)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #416) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #426)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #426)) #("field of our\n" 0 13 (:parent #426)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #426)) #("declaration.\n" 0 13 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #416)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #414))) :mode nil :granularity nil :parent #408) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #414) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #417) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #420)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #418))) :mode nil :granularity nil :parent #414) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #418) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #421) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #424)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #424) #("letsencrypt" 0 11 (:parent #428))) #("via the " 0 8 (:parent #424)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #424) #("certbot" 0 7 (:parent #430))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #424)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #424) #("certbox-service-type" 0 20 (:parent #432))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #424)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #424)) #("field in our " 0 13 (:parent #424)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #424)) #("configuration.\n" 0 15 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #421) #("This service references " 0 24 (:parent #426)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #426)) #(", which we define below. It sends " 0 34 (:parent #426)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #426)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #421) #("Next we define a function we will use later in the " 0 51 (:parent #428)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #428) #("Configure Nginx Server Blocks" 0 29 (:parent #432))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #428))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #421)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #419)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #419))) :mode nil :granularity nil :parent #414) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #419) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #422) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #422)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #422) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #427))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #422) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #431) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #434)) #("\n" 0 1 (:parent #434))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #431) #(" " 0 2 (:parent #435)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #435)) #("provides a route " 0 17 (:parent #435)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #435)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #435)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #435)) #("command). Given away by the reference to " 0 41 (:parent #435)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #435) #("Nix" 0 3 (:parent #445))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #435)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #435) #("Nix Binary Cache" 0 16 (:parent #447))) #(".\n" 0 2 (:parent #435))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #431) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #436))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #431)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #431) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #438))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #431))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #432) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #435)) #("\n" 0 1 (:parent #435))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #432) #(" " 0 2 (:parent #436)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #436) #("NAR (Nix Archive Format)" 0 24 (:parent #440))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #436)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #436) #("hello" 0 5 (:parent #442))) #("package.\n" 0 9 (:parent #436))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #432) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #432)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #432)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #432) #(" The result is composed of a few parts:\n" 0 41 (:parent #440))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #432) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #444))) :mode item :granularity nil :parent #441) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #444) #("the guix store path\n" 0 20 (:parent #447)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #445))) :mode item :granularity nil :parent #441) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #445) #("a hash uniquely identifying the store item\n" 0 43 (:parent #448)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #446))) :mode item :granularity nil :parent #441) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #446) #("the package-name and version, separated by dashes\n" 0 50 (:parent #449))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #432) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #442)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #442)) #(".\n" 0 2 (:parent #442))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #432))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #433) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #436)) #("\n" 0 1 (:parent #436))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #433) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #437)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #437)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #437)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #437)) #("file.\n" 0 6 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #433)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #433)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #433) #(" If the package is not available, this would return a " 0 55 (:parent #440)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #440)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #440)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #440)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #440)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #440)) #("below.\n" 0 7 (:parent #440))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #433) #(" #+begin" 0 9 (:parent #441)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #441) #("src" 0 3 (:parent #445))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #441)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #441) #("nar" 0 3 (:parent #447))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #441)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #441) #("pass" 0 4 (:parent #449))) #("\" url \";\")\n \"client" 0 25 (:parent #441)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #441) #("body" 0 4 (:parent #451))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #441) #("buffer" 0 6 (:parent #452))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #441) #("size" 0 4 (:parent #453))) #("256k;\"\n" 0 7 (:parent #441))))))))))) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #356) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #359) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #362))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #359) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #366) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #369) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #372) #("Improved Build Diversity" 0 24 (:parent #375)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #369)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #367) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #370) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #373) #("Reduced Latency" 0 15 (:parent #376)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #370)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #368) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #371) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #374) #("Increased Resilience" 0 20 (:parent #377)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #371)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #369) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #372) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #375) #("Community Contribution" 0 22 (:parent #378)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #372))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #359) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #364)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #364) #("here" 0 4 (:parent #368))) #(".\n" 0 2 (:parent #364))))) ((other "Why" "Build" "Another" "Substitute" "Server?") . 214174269) ((headline "Why" "Build" "Another" "Substitute" "Server?") . 214174269)) :resolve-fuzzy-link-cache #))
#f(compiled-function (element) #)((headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #0))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #46))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #92) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #95)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #95)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #95)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #95) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #108))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #95) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #109))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #95) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #110))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #95) #("Earlier this year " 0 18 (:parent #111)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #111) #("I announced on the guix mailing list" 0 36 (:parent #115))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #111)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #96))) :mode nil :granularity nil :parent #92) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #96) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #99) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #102))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #99) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #103) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #106) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #109) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #112) #("Improved Build Diversity" 0 24 (:parent #115)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #109)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #103) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #107) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #110) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #113) #("Reduced Latency" 0 15 (:parent #116)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #110)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #103) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #108) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #111) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #114) #("Increased Resilience" 0 20 (:parent #117)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #111)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #103) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #109) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #112) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #115) #("Community Contribution" 0 22 (:parent #118)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #112))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #99) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #104)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #104) #("here" 0 4 (:parent #108))) #(".\n" 0 2 (:parent #104))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #97))) :mode nil :granularity nil :parent #92) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #97) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #100) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #103))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #100) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #107) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #110) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #113) #("Processor" 0 9 (:parent #116)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #110)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #108) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #111) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #114) #("RAM" 0 3 (:parent #117)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #111)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #109) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #112) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #115) #("Storage" 0 7 (:parent #118)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #112)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #110) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #113) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #116) #("Network" 0 7 (:parent #119)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #113)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #111) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #114) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #117) #("Location" 0 8 (:parent #120)))) #(": Memphis TN\n" 0 13 (:parent #114))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #100) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #105))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #100) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #106))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #100) #("For more details, see the " 0 26 (:parent #107)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #107) #("Specifications section" 0 22 (:parent #111))) #("of the Cuirass Manual.\n" 0 23 (:parent #107))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #100) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #108))))) #46)) #0 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #50))) :mode nil :granularity nil :parent #46) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #50) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #53) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #56)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #56) #("guix publish" 0 12 (:parent #60))) #(", which Guix provides the " 0 26 (:parent #56)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #56) #("guix-publish-service-type" 0 25 (:parent #62))) #(",\nwhich is used in the " 0 23 (:parent #56)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #56)) #("field of " 0 9 (:parent #56)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #56)) #("definition.\n" 0 12 (:parent #56))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #53)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #53) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #58))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #51))) :mode nil :granularity nil :parent #46) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #51) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #54) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #57))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #54) #("To anonymize nginx access logs, the " 0 36 (:parent #58)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #58) #("anonip-service-type" 0 19 (:parent #62))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #58)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #58)) #("is defined.\n" 0 12 (:parent #58))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #54)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #54) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #60))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #54)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #54) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #62)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #62)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #62))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #54)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #54) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #64)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #64)) #("field of our\n" 0 13 (:parent #64)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #64)) #("declaration.\n" 0 13 (:parent #64))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #54)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #52))) :mode nil :granularity nil :parent #46) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #52) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #55) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #58)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #56))) :mode nil :granularity nil :parent #52) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #56) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #59) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #62)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #62) #("letsencrypt" 0 11 (:parent #66))) #("via the " 0 8 (:parent #62)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #62) #("certbot" 0 7 (:parent #68))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #62)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #62) #("certbox-service-type" 0 20 (:parent #70))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #62)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #62)) #("field in our " 0 13 (:parent #62)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #62)) #("configuration.\n" 0 15 (:parent #62))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #59)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #59) #("This service references " 0 24 (:parent #64)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #64)) #(", which we define below. It sends " 0 34 (:parent #64)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #64)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #64))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #59)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #59) #("Next we define a function we will use later in the " 0 51 (:parent #66)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #66) #("Configure Nginx Server Blocks" 0 29 (:parent #70))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #66))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #59)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #57)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #57))) :mode nil :granularity nil :parent #52) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #57) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #60) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #63))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #60)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #60) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #65))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #60) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #66) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #69) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #72)) #("\n" 0 1 (:parent #72))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #69) #(" " 0 2 (:parent #73)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #73)) #("provides a route " 0 17 (:parent #73)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #73)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #73)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #73)) #("command). Given away by the reference to " 0 41 (:parent #73)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #73) #("Nix" 0 3 (:parent #83))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #73)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #73) #("Nix Binary Cache" 0 16 (:parent #85))) #(".\n" 0 2 (:parent #73))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #69) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #74))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #69)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #69) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #76))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #69))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #66) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #70) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #73)) #("\n" 0 1 (:parent #73))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #70) #(" " 0 2 (:parent #74)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #74) #("NAR (Nix Archive Format)" 0 24 (:parent #78))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #74)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #74) #("hello" 0 5 (:parent #80))) #("package.\n" 0 9 (:parent #74))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #70) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #75))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #70)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #70)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #70) #(" The result is composed of a few parts:\n" 0 41 (:parent #78))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #70) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #82))) :mode item :granularity nil :parent #79) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #82) #("the guix store path\n" 0 20 (:parent #85)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #83))) :mode item :granularity nil :parent #79) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #83) #("a hash uniquely identifying the store item\n" 0 43 (:parent #86)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #84))) :mode item :granularity nil :parent #79) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #84) #("the package-name and version, separated by dashes\n" 0 50 (:parent #87))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #70) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #80)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #80)) #(".\n" 0 2 (:parent #80))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #70))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #66) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #71) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #74)) #("\n" 0 1 (:parent #74))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #71) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #75)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #75)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #75)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #75)) #("file.\n" 0 6 (:parent #75))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #71)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #71)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #71) #(" If the package is not available, this would return a " 0 55 (:parent #78)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #78)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #78)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #78)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #78)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #78)) #("below.\n" 0 7 (:parent #78))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #71) #(" #+begin" 0 9 (:parent #79)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #79) #("src" 0 3 (:parent #83))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #79)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #79) #("nar" 0 3 (:parent #85))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #79)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #79) #("pass" 0 4 (:parent #87))) #("\" url \";\")\n \"client" 0 25 (:parent #79)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #79) #("body" 0 4 (:parent #89))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #79) #("buffer" 0 6 (:parent #90))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #79) #("size" 0 4 (:parent #91))) #("256k;\"\n" 0 7 (:parent #79)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #0) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #3) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #6)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #6) #("Guix channels" 0 13 (:parent #10))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #6)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #4))) :mode nil :granularity nil :parent #0) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #4) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #7) #("In order to run Cuirass via the " 0 32 (:parent #10)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #10)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #10)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #10)) #("as a " 0 5 (:parent #10)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #10) #("G-Expression" 0 12 (:parent #18))) #("that will return a list of\n" 0 27 (:parent #10)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #10) #("cuirass specifications" 0 22 (:parent #20))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #10))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #7)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #7) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #12)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #12)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #12)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #12) #("Cuirass specification" 0 21 (:parent #18))) #("\ndocumentation for more details.\n" 0 33 (:parent #12))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #7) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #13)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #13) #("Guix Configuration as a Channel" 0 31 (:parent #17))) #(".\n" 0 2 (:parent #13))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #5))) :mode nil :granularity nil :parent #0) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #5) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #8) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #11)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #11)) #("field of our " 0 13 (:parent #11)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #11)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #11))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #8))))))
mapconcat(#f(compiled-function (element) #) ((headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #1))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #47))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #93) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #96)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #96)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #96)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #96)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #96)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #96)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #96)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #96)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #96)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #96)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #96) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #109))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #96) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #110))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #96) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #111))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #96) #("Earlier this year " 0 18 (:parent #112)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #112) #("I announced on the guix mailing list" 0 36 (:parent #116))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #112)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #97))) :mode nil :granularity nil :parent #93) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #97) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #100) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #103))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #100) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #107) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #110) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #113) #("Improved Build Diversity" 0 24 (:parent #116)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #110)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #108) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #111) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #114) #("Reduced Latency" 0 15 (:parent #117)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #111)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #109) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #112) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #115) #("Increased Resilience" 0 20 (:parent #118)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #112)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #104) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #110) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #113) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #116) #("Community Contribution" 0 22 (:parent #119)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #113))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #100) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #105)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #105) #("here" 0 4 (:parent #109))) #(".\n" 0 2 (:parent #105))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #98))) :mode nil :granularity nil :parent #93) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #98) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #101) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #104))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #101) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #108) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #111) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #114) #("Processor" 0 9 (:parent #117)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #111)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #109) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #112) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #115) #("RAM" 0 3 (:parent #118)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #112)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #110) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #113) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #116) #("Storage" 0 7 (:parent #119)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #113)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #111) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #114) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #117) #("Network" 0 7 (:parent #120)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #114)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #112) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #115) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #118) #("Location" 0 8 (:parent #121)))) #(": Memphis TN\n" 0 13 (:parent #115))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #101) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #106))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #101) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #107))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #101) #("For more details, see the " 0 26 (:parent #108)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #108) #("Specifications section" 0 22 (:parent #112))) #("of the Cuirass Manual.\n" 0 23 (:parent #108))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #101) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #109))))) #47)) . #0)) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #1) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #4) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #7)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #7) #("Guix channels" 0 13 (:parent #11))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #7)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #5))) :mode nil :granularity nil :parent #1) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #5) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #8) #("In order to run Cuirass via the " 0 32 (:parent #11)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #11)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #11)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #11)) #("as a " 0 5 (:parent #11)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #11) #("G-Expression" 0 12 (:parent #19))) #("that will return a list of\n" 0 27 (:parent #11)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #11) #("cuirass specifications" 0 22 (:parent #21))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #11))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #8)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #8) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #13)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #13)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #13)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #13) #("Cuirass specification" 0 21 (:parent #19))) #("\ndocumentation for more details.\n" 0 33 (:parent #13))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #8) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #14)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #14) #("Guix Configuration as a Channel" 0 31 (:parent #18))) #(".\n" 0 2 (:parent #14))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #6))) :mode nil :granularity nil :parent #1) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #6) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #9) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #12)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #12)) #("field of our " 0 13 (:parent #12)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #12)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #12))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #9))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #2))) :mode nil :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #48))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #94) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #97)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #97)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #97)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #97)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #97)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #97)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #97)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #97)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #97)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #97)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #97) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #110))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #97) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #111))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #97) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #112))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #97) #("Earlier this year " 0 18 (:parent #113)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #113) #("I announced on the guix mailing list" 0 36 (:parent #117))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #113)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #98))) :mode nil :granularity nil :parent #94) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #98) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #101) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #104))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #101) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #108) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #111) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #114) #("Improved Build Diversity" 0 24 (:parent #117)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #111)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #109) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #112) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #115) #("Reduced Latency" 0 15 (:parent #118)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #112)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #110) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #113) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #116) #("Increased Resilience" 0 20 (:parent #119)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #113)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #105) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #111) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #114) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #117) #("Community Contribution" 0 22 (:parent #120)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #114))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #101) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #106)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #106) #("here" 0 4 (:parent #110))) #(".\n" 0 2 (:parent #106))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #99))) :mode nil :granularity nil :parent #94) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #99) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #102) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #105))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #102) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #109) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #112) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #115) #("Processor" 0 9 (:parent #118)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #112)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #110) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #113) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #116) #("RAM" 0 3 (:parent #119)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #113)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #111) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #114) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #117) #("Storage" 0 7 (:parent #120)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #114)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #112) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #115) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #118) #("Network" 0 7 (:parent #121)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #115)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #113) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #116) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #119) #("Location" 0 8 (:parent #122)))) #(": Memphis TN\n" 0 13 (:parent #116))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #102) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #107))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #102) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #108))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #102) #("For more details, see the " 0 26 (:parent #109)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #109) #("Specifications section" 0 22 (:parent #113))) #("of the Cuirass Manual.\n" 0 23 (:parent #109))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #102) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #110))))) #48)) . #0)) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #2) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #5) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #8)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #8) #("guix publish" 0 12 (:parent #12))) #(", which Guix provides the " 0 26 (:parent #8)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #8) #("guix-publish-service-type" 0 25 (:parent #14))) #(",\nwhich is used in the " 0 23 (:parent #8)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #8)) #("field of " 0 9 (:parent #8)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #8)) #("definition.\n" 0 12 (:parent #8))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #5)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #5) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #10))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #3))) :mode nil :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #49))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #95) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #98)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #98)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #98)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #98)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #98)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #98)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #98)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #98)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #98)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #98)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #98) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #111))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #98) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #112))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #98) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #113))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #98) #("Earlier this year " 0 18 (:parent #114)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #114) #("I announced on the guix mailing list" 0 36 (:parent #118))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #114)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #99))) :mode nil :granularity nil :parent #95) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #99) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #102) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #105))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #102) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #109) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #112) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #115) #("Improved Build Diversity" 0 24 (:parent #118)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #112)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #110) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #113) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #116) #("Reduced Latency" 0 15 (:parent #119)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #113)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #111) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #114) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #117) #("Increased Resilience" 0 20 (:parent #120)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #114)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #106) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #112) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #115) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #118) #("Community Contribution" 0 22 (:parent #121)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #115))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #102) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #107)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #107) #("here" 0 4 (:parent #111))) #(".\n" 0 2 (:parent #107))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #100))) :mode nil :granularity nil :parent #95) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #100) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #103) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #106))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #103) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #110) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #113) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #116) #("Processor" 0 9 (:parent #119)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #113)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #111) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #114) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #117) #("RAM" 0 3 (:parent #120)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #114)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #112) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #115) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #118) #("Storage" 0 7 (:parent #121)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #115)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #113) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #116) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #119) #("Network" 0 7 (:parent #122)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #116)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #114) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #117) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #120) #("Location" 0 8 (:parent #123)))) #(": Memphis TN\n" 0 13 (:parent #117))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #103) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #108))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #103) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #109))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #103) #("For more details, see the " 0 26 (:parent #110)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #110) #("Specifications section" 0 22 (:parent #114))) #("of the Cuirass Manual.\n" 0 23 (:parent #110))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #103) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #111))))) #49)) . #0)) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #3) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #6) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #9))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #6) #("To anonymize nginx access logs, the " 0 36 (:parent #10)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #10) #("anonip-service-type" 0 19 (:parent #14))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #10)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #10)) #("is defined.\n" 0 12 (:parent #10))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #6)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #6) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #12))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #6)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #6) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #14)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #14)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #14))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #6)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #6) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #16)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #16)) #("field of our\n" 0 13 (:parent #16)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #16)) #("declaration.\n" 0 13 (:parent #16))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #6)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #4))) :mode nil :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #50))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #96) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #99)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #99)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #99)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #99)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #99)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #99)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #99)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #99)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #99)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #99)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #99) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #112))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #99) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #113))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #99) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #114))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #99) #("Earlier this year " 0 18 (:parent #115)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #115) #("I announced on the guix mailing list" 0 36 (:parent #119))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #115)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #100))) :mode nil :granularity nil :parent #96) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #100) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #103) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #106))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #103) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #110) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #113) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #116) #("Improved Build Diversity" 0 24 (:parent #119)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #113)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #111) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #114) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #117) #("Reduced Latency" 0 15 (:parent #120)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #114)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #112) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #115) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #118) #("Increased Resilience" 0 20 (:parent #121)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #115)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #107) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #113) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #116) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #119) #("Community Contribution" 0 22 (:parent #122)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #116))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #103) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #108)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #108) #("here" 0 4 (:parent #112))) #(".\n" 0 2 (:parent #108))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #101))) :mode nil :granularity nil :parent #96) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #101) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #104) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #107))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #104) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #108) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #111) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #114) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #117) #("Processor" 0 9 (:parent #120)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #114)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #108) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #112) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #115) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #118) #("RAM" 0 3 (:parent #121)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #115)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #108) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #113) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #116) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #119) #("Storage" 0 7 (:parent #122)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #116)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #108) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #114) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #117) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #120) #("Network" 0 7 (:parent #123)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #117)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #108) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #115) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #118) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #121) #("Location" 0 8 (:parent #124)))) #(": Memphis TN\n" 0 13 (:parent #118))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #104) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #109))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #104) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #110))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #104) #("For more details, see the " 0 26 (:parent #111)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #111) #("Specifications section" 0 22 (:parent #115))) #("of the Cuirass Manual.\n" 0 23 (:parent #111))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #104) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #112))))) #50)) . #0)) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #4) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #7) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #10)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #8))) :mode nil :granularity nil :parent #4) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #8) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #11) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #14)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #14) #("letsencrypt" 0 11 (:parent #18))) #("via the " 0 8 (:parent #14)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #14) #("certbot" 0 7 (:parent #20))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #14)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #14) #("certbox-service-type" 0 20 (:parent #22))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #14)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #14)) #("field in our " 0 13 (:parent #14)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #14)) #("configuration.\n" 0 15 (:parent #14))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #11)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #11) #("This service references " 0 24 (:parent #16)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #16)) #(", which we define below. It sends " 0 34 (:parent #16)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #16)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #16))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #11)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #11) #("Next we define a function we will use later in the " 0 51 (:parent #18)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #18) #("Configure Nginx Server Blocks" 0 29 (:parent #22))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #18))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #11)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #9)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #9))) :mode nil :granularity nil :parent #4) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #9) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #12) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #15))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #12)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #12) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #17))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #12) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #18) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #21) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #24)) #("\n" 0 1 (:parent #24))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #21) #(" " 0 2 (:parent #25)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #25)) #("provides a route " 0 17 (:parent #25)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #25)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #25)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #25)) #("command). Given away by the reference to " 0 41 (:parent #25)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #25) #("Nix" 0 3 (:parent #35))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #25)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #25) #("Nix Binary Cache" 0 16 (:parent #37))) #(".\n" 0 2 (:parent #25))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #21) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #26))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #21)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #21) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #28))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #21))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #18) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #22) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #25)) #("\n" 0 1 (:parent #25))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #22) #(" " 0 2 (:parent #26)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #26) #("NAR (Nix Archive Format)" 0 24 (:parent #30))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #26)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #26) #("hello" 0 5 (:parent #32))) #("package.\n" 0 9 (:parent #26))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #22) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #27))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #22)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #22)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #22) #(" The result is composed of a few parts:\n" 0 41 (:parent #30))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #22) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #34))) :mode item :granularity nil :parent #31) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #34) #("the guix store path\n" 0 20 (:parent #37)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #35))) :mode item :granularity nil :parent #31) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #35) #("a hash uniquely identifying the store item\n" 0 43 (:parent #38)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #36))) :mode item :granularity nil :parent #31) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #36) #("the package-name and version, separated by dashes\n" 0 50 (:parent #39))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #22) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #32)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #32)) #(".\n" 0 2 (:parent #32))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #22))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #18) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #23) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #26)) #("\n" 0 1 (:parent #26))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #23) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #27)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #27)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #27)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #27)) #("file.\n" 0 6 (:parent #27))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #23)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #23)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #23) #(" If the package is not available, this would return a " 0 55 (:parent #30)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #30)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #30)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #30)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #30)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #30)) #("below.\n" 0 7 (:parent #30))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #23) #(" #+begin" 0 9 (:parent #31)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #31) #("src" 0 3 (:parent #35))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #31)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #31) #("nar" 0 3 (:parent #37))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #31)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #31) #("pass" 0 4 (:parent #39))) #("\" url \";\")\n \"client" 0 25 (:parent #31)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #31) #("body" 0 4 (:parent #41))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #31) #("buffer" 0 6 (:parent #42))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #31) #("size" 0 4 (:parent #43))) #("256k;\"\n" 0 7 (:parent #31))))))))) "")
org-export-data((headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #0))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #46) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #49)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #49)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #49) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #62))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #49) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #63))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #49) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #64))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #49) #("Earlier this year " 0 18 (:parent #65)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #65) #("I announced on the guix mailing list" 0 36 (:parent #69))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #65)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #50))) :mode nil :granularity nil :parent #46) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #50) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #53) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #56))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #53) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #57) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #60) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #63) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #66) #("Improved Build Diversity" 0 24 (:parent #69)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #63)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #57) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #61) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #64) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #67) #("Reduced Latency" 0 15 (:parent #70)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #64)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #57) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #62) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #65) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #68) #("Increased Resilience" 0 20 (:parent #71)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #65)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #57) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #63) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #66) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #69) #("Community Contribution" 0 22 (:parent #72)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #66))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #53) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #58)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #58) #("here" 0 4 (:parent #62))) #(".\n" 0 2 (:parent #58))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #51))) :mode nil :granularity nil :parent #46) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #51) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #54) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #57))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #54) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #61) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #64) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #67) #("Processor" 0 9 (:parent #70)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #64)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #62) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #65) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #68) #("RAM" 0 3 (:parent #71)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #65)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #63) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #66) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #69) #("Storage" 0 7 (:parent #72)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #66)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #64) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #67) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #70) #("Network" 0 7 (:parent #73)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #67)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #65) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #68) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #71) #("Location" 0 8 (:parent #74)))) #(": Memphis TN\n" 0 13 (:parent #68))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #54) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #59))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #54) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #60))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #54) #("For more details, see the " 0 26 (:parent #61)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #61) #("Specifications section" 0 22 (:parent #65))) #("of the Cuirass Manual.\n" 0 23 (:parent #61))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #54) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #62))))) #0)) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #3))) :mode section :granularity nil :parent #0) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #3) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #6) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #9)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #9) #("Guix channels" 0 13 (:parent #13))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #9)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #7))) :mode nil :granularity nil :parent #3) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #7) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #10) #("In order to run Cuirass via the " 0 32 (:parent #13)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #13)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #13)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #13)) #("as a " 0 5 (:parent #13)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #13) #("G-Expression" 0 12 (:parent #21))) #("that will return a list of\n" 0 27 (:parent #13)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #13) #("cuirass specifications" 0 22 (:parent #23))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #13))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #10)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #10) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #15)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #15)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #15)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #15) #("Cuirass specification" 0 21 (:parent #21))) #("\ndocumentation for more details.\n" 0 33 (:parent #15))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #10) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #16)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #16) #("Guix Configuration as a Channel" 0 31 (:parent #20))) #(".\n" 0 2 (:parent #16))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #8))) :mode nil :granularity nil :parent #3) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #8) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #11) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #14)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #14)) #("field of our " 0 13 (:parent #14)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #14)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #14))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #11))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #4))) :mode nil :granularity nil :parent #0) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #4) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #7) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #10)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #10) #("guix publish" 0 12 (:parent #14))) #(", which Guix provides the " 0 26 (:parent #10)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #10) #("guix-publish-service-type" 0 25 (:parent #16))) #(",\nwhich is used in the " 0 23 (:parent #10)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #10)) #("field of " 0 9 (:parent #10)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #10)) #("definition.\n" 0 12 (:parent #10))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #7)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #7) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #12))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #5))) :mode nil :granularity nil :parent #0) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #5) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #8) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #11))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #8) #("To anonymize nginx access logs, the " 0 36 (:parent #12)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #12) #("anonip-service-type" 0 19 (:parent #16))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #12)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #12)) #("is defined.\n" 0 12 (:parent #12))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #8)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #8) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #14))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #8)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #8) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #16)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #16)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #16))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #8)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #8) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #18)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #18)) #("field of our\n" 0 13 (:parent #18)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #18)) #("declaration.\n" 0 13 (:parent #18))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #8)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #6))) :mode nil :granularity nil :parent #0) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #6) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #9) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #12)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #10))) :mode nil :granularity nil :parent #6) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #10) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #13) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #16)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #16) #("letsencrypt" 0 11 (:parent #20))) #("via the " 0 8 (:parent #16)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #16) #("certbot" 0 7 (:parent #22))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #16)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #16) #("certbox-service-type" 0 20 (:parent #24))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #16)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #16)) #("field in our " 0 13 (:parent #16)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #16)) #("configuration.\n" 0 15 (:parent #16))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #13)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #13) #("This service references " 0 24 (:parent #18)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #18)) #(", which we define below. It sends " 0 34 (:parent #18)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #18)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #18))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #13)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #13) #("Next we define a function we will use later in the " 0 51 (:parent #20)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #20) #("Configure Nginx Server Blocks" 0 29 (:parent #24))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #20))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #13)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #11)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #11))) :mode nil :granularity nil :parent #6) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #11) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #14) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #17))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #14)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #14) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #19))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #14) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #20) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #23) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #26)) #("\n" 0 1 (:parent #26))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #23) #(" " 0 2 (:parent #27)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #27)) #("provides a route " 0 17 (:parent #27)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #27)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #27)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #27)) #("command). Given away by the reference to " 0 41 (:parent #27)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #27) #("Nix" 0 3 (:parent #37))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #27)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #27) #("Nix Binary Cache" 0 16 (:parent #39))) #(".\n" 0 2 (:parent #27))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #23) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #28))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #23)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #23) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #30))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #23))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #20) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #24) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #27)) #("\n" 0 1 (:parent #27))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #24) #(" " 0 2 (:parent #28)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #28) #("NAR (Nix Archive Format)" 0 24 (:parent #32))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #28)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #28) #("hello" 0 5 (:parent #34))) #("package.\n" 0 9 (:parent #28))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #24) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #29))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #24)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #24)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #24) #(" The result is composed of a few parts:\n" 0 41 (:parent #32))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #24) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #36))) :mode item :granularity nil :parent #33) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #36) #("the guix store path\n" 0 20 (:parent #39)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #37))) :mode item :granularity nil :parent #33) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #37) #("a hash uniquely identifying the store item\n" 0 43 (:parent #40)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #38))) :mode item :granularity nil :parent #33) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #38) #("the package-name and version, separated by dashes\n" 0 50 (:parent #41))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #24) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #34)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #34)) #(".\n" 0 2 (:parent #34))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #24))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #20) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #25) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #28)) #("\n" 0 1 (:parent #28))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #25) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #29)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #29)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #29)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #29)) #("file.\n" 0 6 (:parent #29))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #25)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #25)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #25) #(" If the package is not available, this would return a " 0 55 (:parent #32)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #32)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #32)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #32)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #32)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #32)) #("below.\n" 0 7 (:parent #32))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #25) #(" #+begin" 0 9 (:parent #33)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #33) #("src" 0 3 (:parent #37))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #33)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #33) #("nar" 0 3 (:parent #39))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #33)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #33) #("pass" 0 4 (:parent #41))) #("\" url \";\")\n \"client" 0 25 (:parent #33)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #33) #("body" 0 4 (:parent #43))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #33) #("buffer" 0 6 (:parent #44))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #33) #("size" 0 4 (:parent #45))) #("256k;\"\n" 0 7 (:parent #33))))))))) (:export-options (body-only) :back-end #s(org-export-backend :name html :parent nil :transcoders ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :options ((:html-doctype "HTML_DOCTYPE" nil org-html-doctype) (:html-container "HTML_CONTAINER" nil org-html-container-element) (:html-content-class "HTML_CONTENT_CLASS" nil org-html-content-class) (:description "DESCRIPTION" nil nil newline) (:keywords "KEYWORDS" nil nil space) (:html-html5-fancy nil "html5-fancy" org-html-html5-fancy) (:html-link-use-abs-url nil "html-link-use-abs-url" org-html-link-use-abs-url) (:html-link-home "HTML_LINK_HOME" nil org-html-link-home) (:html-link-up "HTML_LINK_UP" nil org-html-link-up) (:html-mathjax "HTML_MATHJAX" nil "" space) (:html-equation-reference-format "HTML_EQUATION_REFERENCE_FORMAT" nil org-html-equation-reference-format t) (:html-postamble nil "html-postamble" org-html-postamble) (:html-preamble nil "html-preamble" org-html-preamble) (:html-head "HTML_HEAD" nil org-html-head newline) (:html-head-extra "HTML_HEAD_EXTRA" nil org-html-head-extra newline) (:subtitle "SUBTITLE" nil nil parse) (:html-head-include-default-style nil "html-style" org-html-head-include-default-style) (:html-head-include-scripts nil "html-scripts" org-html-head-include-scripts) (:html-allow-name-attribute-in-anchors nil nil org-html-allow-name-attribute-in-anchors) (:html-divs nil nil org-html-divs) (:html-checkbox-type nil nil org-html-checkbox-type) (:html-extension nil nil org-html-extension) (:html-footnote-format nil nil org-html-footnote-format) (:html-footnote-separator nil nil org-html-footnote-separator) (:html-footnotes-section nil nil org-html-footnotes-section) (:html-format-drawer-function nil nil org-html-format-drawer-function) (:html-format-headline-function nil nil org-html-format-headline-function) (:html-format-inlinetask-function nil nil org-html-format-inlinetask-function) (:html-home/up-format nil nil org-html-home/up-format) (:html-indent nil nil org-html-indent) (:html-infojs-options nil nil org-html-infojs-options) (:html-infojs-template nil nil org-html-infojs-template) (:html-inline-image-rules nil nil org-html-inline-image-rules) (:html-link-org-files-as-html nil nil org-html-link-org-files-as-html) (:html-mathjax-options nil nil org-html-mathjax-options) (:html-mathjax-template nil nil org-html-mathjax-template) (:html-metadata-timestamp-format nil nil org-html-metadata-timestamp-format) (:html-postamble-format nil nil org-html-postamble-format) (:html-preamble-format nil nil org-html-preamble-format) (:html-prefer-user-labels nil nil org-html-prefer-user-labels) (:html-self-link-headlines nil nil org-html-self-link-headlines) (:html-table-align-individual-fields nil nil org-html-table-align-individual-fields) (:html-table-caption-above nil nil org-html-table-caption-above) (:html-table-data-tags nil nil org-html-table-data-tags) (:html-table-header-tags nil nil org-html-table-header-tags) (:html-table-use-header-tags-for-first-column nil nil org-html-table-use-header-tags-for-first-column) (:html-tag-class-prefix nil nil org-html-tag-class-prefix) (:html-text-markup-alist nil nil org-html-text-markup-alist) (:html-todo-kwd-class-prefix nil nil org-html-todo-kwd-class-prefix) (:html-toplevel-hlevel nil nil org-html-toplevel-hlevel) (:html-use-infojs nil nil org-html-use-infojs) (:html-validation-link nil nil org-html-validation-link) (:html-viewport nil nil org-html-viewport) (:html-inline-images nil nil org-html-inline-images) (:html-table-attributes nil nil org-html-table-default-attributes) (:html-table-row-open-tag nil nil org-html-table-row-open-tag) (:html-table-row-close-tag nil nil org-html-table-row-close-tag) (:html-xml-declaration nil nil org-html-xml-declaration) (:html-wrap-src-lines nil nil org-html-wrap-src-lines) (:html-klipsify-src nil nil org-html-klipsify-src) (:html-klipse-css nil nil org-html-klipse-css) (:html-klipse-js nil nil org-html-klipse-js) (:html-klipse-selection-script nil nil org-html-klipse-selection-script) (:infojs-opt "INFOJS_OPT" nil nil) (:creator "CREATOR" nil org-html-creator-string) (:with-latex nil "tex" org-html-with-latex) (:latex-header "LATEX_HEADER" nil nil newline)) :filters ((:filter-options . org-html-infojs-install-script) (:filter-parse-tree . org-html-image-link-filter) (:filter-final-output . org-html-final-function)) :blocks nil :menu (104 "Export to HTML" ((72 "As HTML buffer" org-html-export-as-html) (104 "As HTML file" org-html-export-to-html) (111 "As HTML file and open" (lambda (a s v b) (if a (org-html-export-to-html t s v b) (org-open-file (org-html-export-to-html nil s v b)))))))) :translate-alist ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data # :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil :html-divs ((preamble "div" "preamble") (content "div" "content") (postamble "div" "postamble")) :html-checkbox-type ascii :html-extension "html" :html-footnote-format "%s" :html-footnote-separator ", " :html-footnotes-section ") :html-format-headline-function org-html-format-headline-default-function :html-format-inlinetask-function org-html-format-inlinetask-default-function :html-home/up-format "" :html-indent nil :html-infojs-options ((path . "https://orgmode.org/org-info.js") (view . "info") (toc . :with-toc) (ftoc . "0") (tdepth . "max") (sdepth . "max") (mouse . "underline") (buttons . "0") (ltoc . "1") (up . :html-link-up) (home . :html-link-home)) :html-infojs-template "\n\n" :html-inline-image-rules (("file" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("http" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("https" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)")) :html-link-org-files-as-html t :html-mathjax-options ((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js") (scale 1.0) (align "center") (font "mathjax-modern") (overflow "overflow") (tags "ams") (indent "0em") (multlinewidth "85%") (tagindent ".8em") (tagside "right")) :html-mathjax-template "\n\n" :html-metadata-timestamp-format "%Y-%m-%d %a %H:%M" :html-postamble-format (("en" " \n" . " ") :html-table-header-tags ("" . " ") :html-table-use-header-tags-for-first-column nil :html-tag-class-prefix "" :html-text-markup-alist ((bold . "%s") (code . "%s") (underline . "%s") (verbatim . "" :html-table-row-close-tag " " :html-xml-declaration (("html" . "") ("php" . "\"; ?>")) :html-wrap-src-lines nil :html-klipsify-src nil :html-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css" :html-klipse-js "https://storage.googleapis.com/app.klipse.tech/plugin_prod/js/klipse_plugin.min.js" :html-klipse-selection-script "window.klipse_settings = {selector_eval_html: '.src-html',\n selector_eval_js: '.src-js',\n selector_eval_python_client: '.src-python',\n selector_eval_scheme: '.src-scheme',\n selector: '.src-clojure',\n selector_eval_ruby: '.src-ruby'};" :infojs-opt nil :creator "Emacs 29.4 (Org mode 9.6.15)" :with-latex t :latex-header "\\usepackage[margin=1.5cm]{geometry}\n\\usepackage{xcolor}\n\\definecolor{link}{HTML}{506060}\n\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :title (#("Setup of a Simple Guix Build Farm and Substitute Server" 0 55 (:parent #148))) :date nil :author (#("Collin J. Doering" 0 17 (:parent #152))) :email "unknown@genenetwork-development" :language "en" :select-tags ("export") :exclude-tags ("noexport") :headline-levels 3 :preserve-breaks nil :section-numbers nil :time-stamp-file t :with-archived-trees headline :with-author t :with-broken-links nil :with-clocks nil :with-creator nil :with-date t :with-drawers (not "LOGBOOK") :with-email nil :with-emphasize t :with-entities t :with-fixed-width t :with-footnotes t :with-inlinetasks t :with-planning nil :with-priority nil :with-properties nil :with-smart-quotes nil :with-special-strings t :with-statistics-cookies t :with-sub-superscript t :with-toc nil :with-tables t :with-tags t :with-tasks t :with-timestamps t :with-title t :with-todo-keywords t :cite-export (basic nil nil) :bibliography nil :filter-body nil :filter-bold nil :filter-babel-call nil :filter-center-block nil :filter-clock nil :filter-code nil :filter-diary-sexp nil :filter-drawer nil :filter-dynamic-block nil :filter-entity nil :filter-example-block nil :filter-export-block nil :filter-export-snippet nil :filter-final-output (org-html-final-function) :filter-fixed-width nil :filter-footnote-definition nil :filter-footnote-reference nil :filter-headline nil :filter-horizontal-rule nil :filter-inline-babel-call nil :filter-inline-src-block nil :filter-inlinetask nil :filter-italic nil :filter-item nil :filter-keyword nil :filter-latex-environment nil :filter-latex-fragment nil :filter-line-break nil :filter-link nil :filter-node-property nil :filter-options (org-html-infojs-install-script) :filter-paragraph nil :filter-parse-tree (org-html-image-link-filter) :filter-plain-list nil :filter-plain-text nil :filter-planning nil :filter-property-drawer nil :filter-quote-block nil :filter-radio-target nil :filter-section nil :filter-special-block nil :filter-src-block nil :filter-statistics-cookie nil :filter-strike-through nil :filter-subscript nil :filter-superscript nil :filter-table nil :filter-table-cell nil :filter-table-row nil :filter-target nil :filter-timestamp nil :filter-underline nil :filter-verbatim nil :filter-verse-block nil :ignore-list nil :parse-tree (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #338) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #341)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #341)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #341) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #354))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #341) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #355))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #341) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #356))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #341) #("Earlier this year " 0 18 (:parent #357)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #357) #("I announced on the guix mailing list" 0 36 (:parent #361))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #357)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #342))) :mode nil :granularity nil :parent #338) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #342) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #345) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #348))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #345) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #352) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #355) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #358) #("Improved Build Diversity" 0 24 (:parent #361)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #355)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #353) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #356) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #359) #("Reduced Latency" 0 15 (:parent #362)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #356)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #354) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #357) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #360) #("Increased Resilience" 0 20 (:parent #363)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #357)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #355) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #358) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #361) #("Community Contribution" 0 22 (:parent #364)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #358))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #345) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #350)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #350) #("here" 0 4 (:parent #354))) #(".\n" 0 2 (:parent #350))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #343))) :mode nil :granularity nil :parent #338) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #343) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #346) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #349))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #346) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #353) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #356) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #359) #("Processor" 0 9 (:parent #362)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #356)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #354) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #357) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #360) #("RAM" 0 3 (:parent #363)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #357)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #355) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #358) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #361) #("Storage" 0 7 (:parent #364)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #358)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #356) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #359) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #362) #("Network" 0 7 (:parent #365)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #359)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #357) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #360) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #363) #("Location" 0 8 (:parent #366)))) #(": Memphis TN\n" 0 13 (:parent #360))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #346) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #351))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #346) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #352))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #346) #("For more details, see the " 0 26 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #353) #("Specifications section" 0 22 (:parent #357))) #("of the Cuirass Manual.\n" 0 23 (:parent #353))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #346) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #354))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #344))) :mode nil :granularity nil :parent #338) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #347))) :mode section :granularity nil :parent #344) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #347) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #350) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #353) #("Guix channels" 0 13 (:parent #357))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #353)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #351))) :mode nil :granularity nil :parent #347) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #351) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #354) #("In order to run Cuirass via the " 0 32 (:parent #357)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #357)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #357)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #357)) #("as a " 0 5 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #357) #("G-Expression" 0 12 (:parent #365))) #("that will return a list of\n" 0 27 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #357) #("cuirass specifications" 0 22 (:parent #367))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #357))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #354)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #354) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #359)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #359)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #359)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #359) #("Cuirass specification" 0 21 (:parent #365))) #("\ndocumentation for more details.\n" 0 33 (:parent #359))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #354) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #360)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #360) #("Guix Configuration as a Channel" 0 31 (:parent #364))) #(".\n" 0 2 (:parent #360))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #352))) :mode nil :granularity nil :parent #347) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #352) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #355) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #358)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #358)) #("field of our " 0 13 (:parent #358)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #358)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #355))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #348))) :mode nil :granularity nil :parent #344) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #348) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #351) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #354)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #354) #("guix publish" 0 12 (:parent #358))) #(", which Guix provides the " 0 26 (:parent #354)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #354) #("guix-publish-service-type" 0 25 (:parent #360))) #(",\nwhich is used in the " 0 23 (:parent #354)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #354)) #("field of " 0 9 (:parent #354)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #354)) #("definition.\n" 0 12 (:parent #354))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #351)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #351) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #356))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #349))) :mode nil :granularity nil :parent #344) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #349) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #352) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #355))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #352) #("To anonymize nginx access logs, the " 0 36 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #356) #("anonip-service-type" 0 19 (:parent #360))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #356)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #356)) #("is defined.\n" 0 12 (:parent #356))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #352) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #352) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #360)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #360)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #352)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #352) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #362)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #362)) #("field of our\n" 0 13 (:parent #362)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #362)) #("declaration.\n" 0 13 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #352)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #350))) :mode nil :granularity nil :parent #344) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #350) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #353) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #356)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #354) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #357) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #360)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #360) #("letsencrypt" 0 11 (:parent #364))) #("via the " 0 8 (:parent #360)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #360) #("certbot" 0 7 (:parent #366))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #360) #("certbox-service-type" 0 20 (:parent #368))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #360)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #360)) #("field in our " 0 13 (:parent #360)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #360)) #("configuration.\n" 0 15 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #357) #("This service references " 0 24 (:parent #362)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #362)) #(", which we define below. It sends " 0 34 (:parent #362)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #362)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #357) #("Next we define a function we will use later in the " 0 51 (:parent #364)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #364) #("Configure Nginx Server Blocks" 0 29 (:parent #368))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #364))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #357)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #355)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #355) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #358) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #358)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #358) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #363))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #358) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #367) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #370)) #("\n" 0 1 (:parent #370))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #367) #(" " 0 2 (:parent #371)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #371)) #("provides a route " 0 17 (:parent #371)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #371)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #371)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #371)) #("command). Given away by the reference to " 0 41 (:parent #371)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #371) #("Nix" 0 3 (:parent #381))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #371)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #371) #("Nix Binary Cache" 0 16 (:parent #383))) #(".\n" 0 2 (:parent #371))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #367) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #372))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #367)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #367) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #374))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #367))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #368) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #371)) #("\n" 0 1 (:parent #371))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #368) #(" " 0 2 (:parent #372)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #372) #("NAR (Nix Archive Format)" 0 24 (:parent #376))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #372)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #372) #("hello" 0 5 (:parent #378))) #("package.\n" 0 9 (:parent #372))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #368) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #368)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #368)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #368) #(" The result is composed of a few parts:\n" 0 41 (:parent #376))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #368) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #380))) :mode item :granularity nil :parent #377) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #380) #("the guix store path\n" 0 20 (:parent #383)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #381))) :mode item :granularity nil :parent #377) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #381) #("a hash uniquely identifying the store item\n" 0 43 (:parent #384)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #382))) :mode item :granularity nil :parent #377) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #382) #("the package-name and version, separated by dashes\n" 0 50 (:parent #385))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #368) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #378)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #378)) #(".\n" 0 2 (:parent #378))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #368))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #369) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #372)) #("\n" 0 1 (:parent #372))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #369) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #373)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #373)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #373)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #373)) #("file.\n" 0 6 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #369)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #369)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #369) #(" If the package is not available, this would return a " 0 55 (:parent #376)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #376)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #376)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #376)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #376)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #376)) #("below.\n" 0 7 (:parent #376))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #369) #(" #+begin" 0 9 (:parent #377)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #377) #("src" 0 3 (:parent #381))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #377)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #377) #("nar" 0 3 (:parent #383))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #377)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #377) #("pass" 0 4 (:parent #385))) #("\" url \";\")\n \"client" 0 25 (:parent #377)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #377) #("body" 0 4 (:parent #387))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #377) #("buffer" 0 6 (:parent #388))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #377) #("size" 0 4 (:parent #389))) #("256k;\"\n" 0 7 (:parent #377)))))))))) :headline-offset 0 :headline-numbering nil :id-alist nil :citations nil :internal-references (("org1d65611" headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #350))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #396))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #442) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #445)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #445)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #445) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #458))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #445) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #459))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #445) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #460))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #445) #("Earlier this year " 0 18 (:parent #461)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #461) #("I announced on the guix mailing list" 0 36 (:parent #465))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #461)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #446))) :mode nil :granularity nil :parent #442) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #446) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #449) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #452))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #449) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #456) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #459) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #462) #("Improved Build Diversity" 0 24 (:parent #465)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #459)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #457) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #460) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #463) #("Reduced Latency" 0 15 (:parent #466)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #460)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #458) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #461) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #464) #("Increased Resilience" 0 20 (:parent #467)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #461)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #459) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #462) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #465) #("Community Contribution" 0 22 (:parent #468)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #462))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #449) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #454)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #454) #("here" 0 4 (:parent #458))) #(".\n" 0 2 (:parent #454))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #447))) :mode nil :granularity nil :parent #442) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #447) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #450) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #453))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #450) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #457) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #460) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #463) #("Processor" 0 9 (:parent #466)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #460)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #458) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #461) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #464) #("RAM" 0 3 (:parent #467)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #461)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #459) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #462) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #465) #("Storage" 0 7 (:parent #468)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #462)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #460) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #463) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #466) #("Network" 0 7 (:parent #469)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #463)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #461) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #464) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #467) #("Location" 0 8 (:parent #470)))) #(": Memphis TN\n" 0 13 (:parent #464))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #450) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #455))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #450) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #456))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #450) #("For more details, see the " 0 26 (:parent #457)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #457) #("Specifications section" 0 22 (:parent #461))) #("of the Cuirass Manual.\n" 0 23 (:parent #457))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #450) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #458))))) #396)) #350 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #400))) :mode nil :granularity nil :parent #396) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #400) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #403) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #406)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #406) #("guix publish" 0 12 (:parent #410))) #(", which Guix provides the " 0 26 (:parent #406)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #406) #("guix-publish-service-type" 0 25 (:parent #412))) #(",\nwhich is used in the " 0 23 (:parent #406)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #406)) #("field of " 0 9 (:parent #406)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #406)) #("definition.\n" 0 12 (:parent #406))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #403)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #403) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #408))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #401))) :mode nil :granularity nil :parent #396) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #401) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #404) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #407))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #404) #("To anonymize nginx access logs, the " 0 36 (:parent #408)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #408) #("anonip-service-type" 0 19 (:parent #412))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #408)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #408)) #("is defined.\n" 0 12 (:parent #408))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #404) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #410))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #404) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #412)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #412)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #404)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #404) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #414)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #414)) #("field of our\n" 0 13 (:parent #414)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #414)) #("declaration.\n" 0 13 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #404)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #402))) :mode nil :granularity nil :parent #396) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #402) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #405) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #408)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #406))) :mode nil :granularity nil :parent #402) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #406) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #409) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #412)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #412) #("letsencrypt" 0 11 (:parent #416))) #("via the " 0 8 (:parent #412)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #412) #("certbot" 0 7 (:parent #418))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #412)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #412) #("certbox-service-type" 0 20 (:parent #420))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #412)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #412)) #("field in our " 0 13 (:parent #412)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #412)) #("configuration.\n" 0 15 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #409) #("This service references " 0 24 (:parent #414)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #414)) #(", which we define below. It sends " 0 34 (:parent #414)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #414)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #409) #("Next we define a function we will use later in the " 0 51 (:parent #416)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #416) #("Configure Nginx Server Blocks" 0 29 (:parent #420))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #416))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #409)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #407)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #407) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #410) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #413))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #410)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #410) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #415))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #419) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #422)) #("\n" 0 1 (:parent #422))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #419) #(" " 0 2 (:parent #423)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #423)) #("provides a route " 0 17 (:parent #423)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #423)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #423)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #423)) #("command). Given away by the reference to " 0 41 (:parent #423)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #423) #("Nix" 0 3 (:parent #433))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #423)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #423) #("Nix Binary Cache" 0 16 (:parent #435))) #(".\n" 0 2 (:parent #423))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #419) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #424))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #419)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #419) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #419))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #420) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #423)) #("\n" 0 1 (:parent #423))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #420) #(" " 0 2 (:parent #424)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #424) #("NAR (Nix Archive Format)" 0 24 (:parent #428))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #424)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #424) #("hello" 0 5 (:parent #430))) #("package.\n" 0 9 (:parent #424))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #420) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #420)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #420)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #420) #(" The result is composed of a few parts:\n" 0 41 (:parent #428))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #420) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #432))) :mode item :granularity nil :parent #429) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #432) #("the guix store path\n" 0 20 (:parent #435)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #433))) :mode item :granularity nil :parent #429) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #433) #("a hash uniquely identifying the store item\n" 0 43 (:parent #436)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #434))) :mode item :granularity nil :parent #429) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #434) #("the package-name and version, separated by dashes\n" 0 50 (:parent #437))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #420) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #430)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #430)) #(".\n" 0 2 (:parent #430))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #420))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #421) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #424)) #("\n" 0 1 (:parent #424))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #421) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #425)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #425)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #425)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #425)) #("file.\n" 0 6 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #421)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #421)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #421) #(" If the package is not available, this would return a " 0 55 (:parent #428)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #428)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #428)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #428)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #428)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #428)) #("below.\n" 0 7 (:parent #428))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #421) #(" #+begin" 0 9 (:parent #429)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #429) #("src" 0 3 (:parent #433))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #429)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #429) #("nar" 0 3 (:parent #435))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #429)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #429) #("pass" 0 4 (:parent #437))) #("\" url \";\")\n \"client" 0 25 (:parent #429)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #429) #("body" 0 4 (:parent #439))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #429) #("buffer" 0 6 (:parent #440))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #429) #("size" 0 4 (:parent #441))) #("256k;\"\n" 0 7 (:parent #429)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #350) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #353) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #356) #("Guix channels" 0 13 (:parent #360))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #356)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #354) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #357) #("In order to run Cuirass via the " 0 32 (:parent #360)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #360)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #360)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #360)) #("as a " 0 5 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #360) #("G-Expression" 0 12 (:parent #368))) #("that will return a list of\n" 0 27 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #360) #("cuirass specifications" 0 22 (:parent #370))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #357)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #357) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #362)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #362)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #362)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #362) #("Cuirass specification" 0 21 (:parent #368))) #("\ndocumentation for more details.\n" 0 33 (:parent #362))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #357) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #363)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #363) #("Guix Configuration as a Channel" 0 31 (:parent #367))) #(".\n" 0 2 (:parent #363))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #355) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #358) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #361)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #361)) #("field of our " 0 13 (:parent #361)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #361)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #358))))) ((other "Cuirass" "-" "Building" "Packages") . 30823953) ((headline "Cuirass" "-" "Building" "Packages") . 30823953) ("org46b8c57" headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #353))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #399) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #402)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #402)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #402) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #415))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #402) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #416))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #402) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #417))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #402) #("Earlier this year " 0 18 (:parent #418)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #418) #("I announced on the guix mailing list" 0 36 (:parent #422))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #418)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #403))) :mode nil :granularity nil :parent #399) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #403) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #406) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #409))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #406) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #413) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #416) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #419) #("Improved Build Diversity" 0 24 (:parent #422)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #416)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #414) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #417) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #420) #("Reduced Latency" 0 15 (:parent #423)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #417)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #415) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #418) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #421) #("Increased Resilience" 0 20 (:parent #424)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #418)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #416) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #419) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #422) #("Community Contribution" 0 22 (:parent #425)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #419))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #406) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #411)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #411) #("here" 0 4 (:parent #415))) #(".\n" 0 2 (:parent #411))))) #353 (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #405))) :mode nil :granularity nil :parent #399) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #408))) :mode section :granularity nil :parent #405) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #408) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #411) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #414)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #414) #("Guix channels" 0 13 (:parent #418))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #414)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #412) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #415) #("In order to run Cuirass via the " 0 32 (:parent #418)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #418)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #418)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #418)) #("as a " 0 5 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #418) #("G-Expression" 0 12 (:parent #426))) #("that will return a list of\n" 0 27 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #418) #("cuirass specifications" 0 22 (:parent #428))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #415)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #415) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #420)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #420)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #420) #("Cuirass specification" 0 21 (:parent #426))) #("\ndocumentation for more details.\n" 0 33 (:parent #420))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #415) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #421)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #421) #("Guix Configuration as a Channel" 0 31 (:parent #425))) #(".\n" 0 2 (:parent #421))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #413) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #416) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #419)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #419)) #("field of our " 0 13 (:parent #419)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #419)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #416))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #409))) :mode nil :granularity nil :parent #405) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #409) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #412) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #415)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #415) #("guix publish" 0 12 (:parent #419))) #(", which Guix provides the " 0 26 (:parent #415)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #415) #("guix-publish-service-type" 0 25 (:parent #421))) #(",\nwhich is used in the " 0 23 (:parent #415)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #415)) #("field of " 0 9 (:parent #415)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #415)) #("definition.\n" 0 12 (:parent #415))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #412)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #412) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #417))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #410))) :mode nil :granularity nil :parent #405) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #410) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #413) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #416))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #413) #("To anonymize nginx access logs, the " 0 36 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #417) #("anonip-service-type" 0 19 (:parent #421))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #417)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #417)) #("is defined.\n" 0 12 (:parent #417))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #413) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #413) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #421)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #421)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #413)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #413) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #423)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #423)) #("field of our\n" 0 13 (:parent #423)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #423)) #("declaration.\n" 0 13 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #413)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #411))) :mode nil :granularity nil :parent #405) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #411) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #414) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #417)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #415) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #418) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #421)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #421) #("letsencrypt" 0 11 (:parent #425))) #("via the " 0 8 (:parent #421)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #421) #("certbot" 0 7 (:parent #427))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #421) #("certbox-service-type" 0 20 (:parent #429))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #421)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #421)) #("field in our " 0 13 (:parent #421)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #421)) #("configuration.\n" 0 15 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #418) #("This service references " 0 24 (:parent #423)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #423)) #(", which we define below. It sends " 0 34 (:parent #423)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #423)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #418) #("Next we define a function we will use later in the " 0 51 (:parent #425)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #425) #("Configure Nginx Server Blocks" 0 29 (:parent #429))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #418)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #416)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #416) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #419) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #419)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #419) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #424))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #419) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #428) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #431)) #("\n" 0 1 (:parent #431))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #428) #(" " 0 2 (:parent #432)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #432)) #("provides a route " 0 17 (:parent #432)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #432)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #432)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #432)) #("command). Given away by the reference to " 0 41 (:parent #432)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #432) #("Nix" 0 3 (:parent #442))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #432)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #432) #("Nix Binary Cache" 0 16 (:parent #444))) #(".\n" 0 2 (:parent #432))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #428) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #433))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #428)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #428) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #435))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #428))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #429) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #432)) #("\n" 0 1 (:parent #432))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #429) #(" " 0 2 (:parent #433)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #433) #("NAR (Nix Archive Format)" 0 24 (:parent #437))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #433)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #433) #("hello" 0 5 (:parent #439))) #("package.\n" 0 9 (:parent #433))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #429) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #429)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #429)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #429) #(" The result is composed of a few parts:\n" 0 41 (:parent #437))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #429) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #441))) :mode item :granularity nil :parent #438) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #441) #("the guix store path\n" 0 20 (:parent #444)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #442))) :mode item :granularity nil :parent #438) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #442) #("a hash uniquely identifying the store item\n" 0 43 (:parent #445)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #443))) :mode item :granularity nil :parent #438) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #443) #("the package-name and version, separated by dashes\n" 0 50 (:parent #446))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #429) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #439)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #439)) #(".\n" 0 2 (:parent #439))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #429))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #430) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #433)) #("\n" 0 1 (:parent #433))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #430) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #434)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #434)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #434)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #434)) #("file.\n" 0 6 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #430)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #430)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #430) #(" If the package is not available, this would return a " 0 55 (:parent #437)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #437)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #437)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #437)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #437)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #437)) #("below.\n" 0 7 (:parent #437))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #430) #(" #+begin" 0 9 (:parent #438)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #438) #("src" 0 3 (:parent #442))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #438)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #438) #("nar" 0 3 (:parent #444))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #438)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #438) #("pass" 0 4 (:parent #446))) #("\" url \";\")\n \"client" 0 25 (:parent #438)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #438) #("body" 0 4 (:parent #448))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #438) #("buffer" 0 6 (:parent #449))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #438) #("size" 0 4 (:parent #450))) #("256k;\"\n" 0 7 (:parent #438))))))))))) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #353) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #356) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #359))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #356) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #363) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #366) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #369) #("Processor" 0 9 (:parent #372)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #366)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #364) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #367) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #370) #("RAM" 0 3 (:parent #373)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #367)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #365) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #368) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #371) #("Storage" 0 7 (:parent #374)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #368)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #366) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #369) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #372) #("Network" 0 7 (:parent #375)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #369)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #367) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #370) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #373) #("Location" 0 8 (:parent #376)))) #(": Memphis TN\n" 0 13 (:parent #370))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #356) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #361))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #356) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #362))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #356) #("For more details, see the " 0 26 (:parent #363)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #363) #("Specifications section" 0 22 (:parent #367))) #("of the Cuirass Manual.\n" 0 23 (:parent #363))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #356) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #364))))) ((other "Hardware" "and" "Infrastructure") . 74157143) ((headline "Hardware" "and" "Infrastructure") . 74157143) ("orgcc40a3d" headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #356))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #402) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #405)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #405)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #405) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #418))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #405) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #419))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #405) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #420))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #405) #("Earlier this year " 0 18 (:parent #421)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #421) #("I announced on the guix mailing list" 0 36 (:parent #425))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #421)))) #356 (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #407) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #410) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #413))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #417) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #420) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #423) #("Processor" 0 9 (:parent #426)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #420)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #418) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #421) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #424) #("RAM" 0 3 (:parent #427)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #421)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #419) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #422) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #425) #("Storage" 0 7 (:parent #428)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #422)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #420) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #423) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #426) #("Network" 0 7 (:parent #429)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #423)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #421) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #424) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #427) #("Location" 0 8 (:parent #430)))) #(": Memphis TN\n" 0 13 (:parent #424))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #410) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #415))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #410) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #416))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #410) #("For more details, see the " 0 26 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #417) #("Specifications section" 0 22 (:parent #421))) #("of the Cuirass Manual.\n" 0 23 (:parent #417))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #410) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #418))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #408))) :mode nil :granularity nil :parent #402) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #411))) :mode section :granularity nil :parent #408) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #411) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #414) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #417) #("Guix channels" 0 13 (:parent #421))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #417)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #415) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #418) #("In order to run Cuirass via the " 0 32 (:parent #421)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #421)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #421)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #421)) #("as a " 0 5 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #421) #("G-Expression" 0 12 (:parent #429))) #("that will return a list of\n" 0 27 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #421) #("cuirass specifications" 0 22 (:parent #431))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #418)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #418) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #423)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #423)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #423)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #423) #("Cuirass specification" 0 21 (:parent #429))) #("\ndocumentation for more details.\n" 0 33 (:parent #423))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #418) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #424)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #424) #("Guix Configuration as a Channel" 0 31 (:parent #428))) #(".\n" 0 2 (:parent #424))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #416) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #419) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #422)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #422)) #("field of our " 0 13 (:parent #422)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #422)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #419))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #412) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #415) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #418) #("guix publish" 0 12 (:parent #422))) #(", which Guix provides the " 0 26 (:parent #418)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #418) #("guix-publish-service-type" 0 25 (:parent #424))) #(",\nwhich is used in the " 0 23 (:parent #418)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #418)) #("field of " 0 9 (:parent #418)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #418)) #("definition.\n" 0 12 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #415)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #415) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #420))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #413) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #416) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #419))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #416) #("To anonymize nginx access logs, the " 0 36 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #420) #("anonip-service-type" 0 19 (:parent #424))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #420)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #420)) #("is defined.\n" 0 12 (:parent #420))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #416) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #416) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #424)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #424)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #416)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #416) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #426)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #426)) #("field of our\n" 0 13 (:parent #426)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #426)) #("declaration.\n" 0 13 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #416)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #414))) :mode nil :granularity nil :parent #408) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #414) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #417) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #420)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #418))) :mode nil :granularity nil :parent #414) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #418) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #421) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #424)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #424) #("letsencrypt" 0 11 (:parent #428))) #("via the " 0 8 (:parent #424)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #424) #("certbot" 0 7 (:parent #430))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #424)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #424) #("certbox-service-type" 0 20 (:parent #432))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #424)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #424)) #("field in our " 0 13 (:parent #424)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #424)) #("configuration.\n" 0 15 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #421) #("This service references " 0 24 (:parent #426)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #426)) #(", which we define below. It sends " 0 34 (:parent #426)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #426)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #421) #("Next we define a function we will use later in the " 0 51 (:parent #428)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #428) #("Configure Nginx Server Blocks" 0 29 (:parent #432))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #428))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #421)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #419)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #419))) :mode nil :granularity nil :parent #414) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #419) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #422) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #422)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #422) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #427))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #422) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #431) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #434)) #("\n" 0 1 (:parent #434))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #431) #(" " 0 2 (:parent #435)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #435)) #("provides a route " 0 17 (:parent #435)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #435)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #435)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #435)) #("command). Given away by the reference to " 0 41 (:parent #435)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #435) #("Nix" 0 3 (:parent #445))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #435)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #435) #("Nix Binary Cache" 0 16 (:parent #447))) #(".\n" 0 2 (:parent #435))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #431) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #436))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #431)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #431) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #438))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #431))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #432) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #435)) #("\n" 0 1 (:parent #435))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #432) #(" " 0 2 (:parent #436)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #436) #("NAR (Nix Archive Format)" 0 24 (:parent #440))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #436)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #436) #("hello" 0 5 (:parent #442))) #("package.\n" 0 9 (:parent #436))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #432) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #432)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #432)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #432) #(" The result is composed of a few parts:\n" 0 41 (:parent #440))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #432) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #444))) :mode item :granularity nil :parent #441) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #444) #("the guix store path\n" 0 20 (:parent #447)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #445))) :mode item :granularity nil :parent #441) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #445) #("a hash uniquely identifying the store item\n" 0 43 (:parent #448)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #446))) :mode item :granularity nil :parent #441) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #446) #("the package-name and version, separated by dashes\n" 0 50 (:parent #449))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #432) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #442)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #442)) #(".\n" 0 2 (:parent #442))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #432))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #433) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #436)) #("\n" 0 1 (:parent #436))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #433) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #437)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #437)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #437)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #437)) #("file.\n" 0 6 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #433)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #433)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #433) #(" If the package is not available, this would return a " 0 55 (:parent #440)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #440)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #440)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #440)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #440)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #440)) #("below.\n" 0 7 (:parent #440))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #433) #(" #+begin" 0 9 (:parent #441)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #441) #("src" 0 3 (:parent #445))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #441)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #441) #("nar" 0 3 (:parent #447))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #441)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #441) #("pass" 0 4 (:parent #449))) #("\" url \";\")\n \"client" 0 25 (:parent #441)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #441) #("body" 0 4 (:parent #451))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #441) #("buffer" 0 6 (:parent #452))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #441) #("size" 0 4 (:parent #453))) #("256k;\"\n" 0 7 (:parent #441))))))))))) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #356) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #359) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #362))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #359) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #366) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #369) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #372) #("Improved Build Diversity" 0 24 (:parent #375)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #369)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #367) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #370) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #373) #("Reduced Latency" 0 15 (:parent #376)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #370)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #368) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #371) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #374) #("Increased Resilience" 0 20 (:parent #377)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #371)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #369) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #372) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #375) #("Community Contribution" 0 22 (:parent #378)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #372))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #359) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #364)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #364) #("here" 0 4 (:parent #368))) #(".\n" 0 2 (:parent #364))))) ((other "Why" "Build" "Another" "Substitute" "Server?") . 214174269) ((headline "Why" "Build" "Another" "Substitute" "Server?") . 214174269)) :resolve-fuzzy-link-cache #))
#f(compiled-function (element) #)((headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #0))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #46) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #49)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #49)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #49)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #49) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #62))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #49) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #63))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #49) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #64))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #49) #("Earlier this year " 0 18 (:parent #65)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #65) #("I announced on the guix mailing list" 0 36 (:parent #69))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #65)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #50))) :mode nil :granularity nil :parent #46) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #50) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #53) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #56))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #53) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #57) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #60) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #63) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #66) #("Improved Build Diversity" 0 24 (:parent #69)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #63)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #57) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #61) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #64) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #67) #("Reduced Latency" 0 15 (:parent #70)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #64)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #57) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #62) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #65) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #68) #("Increased Resilience" 0 20 (:parent #71)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #65)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #57) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #63) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #66) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #69) #("Community Contribution" 0 22 (:parent #72)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #66))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #53) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #58)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #58) #("here" 0 4 (:parent #62))) #(".\n" 0 2 (:parent #58))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #51))) :mode nil :granularity nil :parent #46) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #51) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #54) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #57))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #54) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #61) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #64) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #67) #("Processor" 0 9 (:parent #70)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #64)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #62) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #65) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #68) #("RAM" 0 3 (:parent #71)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #65)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #63) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #66) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #69) #("Storage" 0 7 (:parent #72)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #66)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #64) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #67) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #70) #("Network" 0 7 (:parent #73)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #67)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #58) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #65) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #68) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #71) #("Location" 0 8 (:parent #74)))) #(": Memphis TN\n" 0 13 (:parent #68))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #54) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #59))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #54) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #60))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #54) #("For more details, see the " 0 26 (:parent #61)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #61) #("Specifications section" 0 22 (:parent #65))) #("of the Cuirass Manual.\n" 0 23 (:parent #61))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #54) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #62))))) #0)) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #3))) :mode section :granularity nil :parent #0) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #3) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #6) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #9)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #9) #("Guix channels" 0 13 (:parent #13))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #9)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #7))) :mode nil :granularity nil :parent #3) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #7) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #10) #("In order to run Cuirass via the " 0 32 (:parent #13)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #13)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #13)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #13)) #("as a " 0 5 (:parent #13)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #13) #("G-Expression" 0 12 (:parent #21))) #("that will return a list of\n" 0 27 (:parent #13)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #13) #("cuirass specifications" 0 22 (:parent #23))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #13))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #10)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #10) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #15)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #15)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #15)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #15) #("Cuirass specification" 0 21 (:parent #21))) #("\ndocumentation for more details.\n" 0 33 (:parent #15))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #10) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #16)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #16) #("Guix Configuration as a Channel" 0 31 (:parent #20))) #(".\n" 0 2 (:parent #16))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #8))) :mode nil :granularity nil :parent #3) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #8) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #11) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #14)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #14)) #("field of our " 0 13 (:parent #14)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #14)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #14))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #11))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #4))) :mode nil :granularity nil :parent #0) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #4) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #7) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #10)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #10) #("guix publish" 0 12 (:parent #14))) #(", which Guix provides the " 0 26 (:parent #10)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #10) #("guix-publish-service-type" 0 25 (:parent #16))) #(",\nwhich is used in the " 0 23 (:parent #10)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #10)) #("field of " 0 9 (:parent #10)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #10)) #("definition.\n" 0 12 (:parent #10))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #7)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #7) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #12))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #5))) :mode nil :granularity nil :parent #0) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #5) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #8) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #11))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #8) #("To anonymize nginx access logs, the " 0 36 (:parent #12)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #12) #("anonip-service-type" 0 19 (:parent #16))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #12)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #12)) #("is defined.\n" 0 12 (:parent #12))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #8)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #8) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #14))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #8)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #8) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #16)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #16)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #16))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #8)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #8) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #18)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #18)) #("field of our\n" 0 13 (:parent #18)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #18)) #("declaration.\n" 0 13 (:parent #18))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #8)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #6))) :mode nil :granularity nil :parent #0) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #6) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #9) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #12)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #10))) :mode nil :granularity nil :parent #6) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #10) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #13) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #16)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #16) #("letsencrypt" 0 11 (:parent #20))) #("via the " 0 8 (:parent #16)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #16) #("certbot" 0 7 (:parent #22))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #16)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #16) #("certbox-service-type" 0 20 (:parent #24))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #16)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #16)) #("field in our " 0 13 (:parent #16)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #16)) #("configuration.\n" 0 15 (:parent #16))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #13)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #13) #("This service references " 0 24 (:parent #18)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #18)) #(", which we define below. It sends " 0 34 (:parent #18)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #18)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #18))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #13)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #13) #("Next we define a function we will use later in the " 0 51 (:parent #20)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #20) #("Configure Nginx Server Blocks" 0 29 (:parent #24))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #20))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #13)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #11)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #11))) :mode nil :granularity nil :parent #6) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #11) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #14) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #17))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #14)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #14) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #19))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #14) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #20) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #23) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #26)) #("\n" 0 1 (:parent #26))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #23) #(" " 0 2 (:parent #27)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #27)) #("provides a route " 0 17 (:parent #27)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #27)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #27)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #27)) #("command). Given away by the reference to " 0 41 (:parent #27)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #27) #("Nix" 0 3 (:parent #37))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #27)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #27) #("Nix Binary Cache" 0 16 (:parent #39))) #(".\n" 0 2 (:parent #27))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #23) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #28))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #23)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #23) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #30))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #23))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #20) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #24) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #27)) #("\n" 0 1 (:parent #27))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #24) #(" " 0 2 (:parent #28)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #28) #("NAR (Nix Archive Format)" 0 24 (:parent #32))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #28)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #28) #("hello" 0 5 (:parent #34))) #("package.\n" 0 9 (:parent #28))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #24) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #29))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #24)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #24)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #24) #(" The result is composed of a few parts:\n" 0 41 (:parent #32))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #24) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #36))) :mode item :granularity nil :parent #33) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #36) #("the guix store path\n" 0 20 (:parent #39)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #37))) :mode item :granularity nil :parent #33) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #37) #("a hash uniquely identifying the store item\n" 0 43 (:parent #40)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #38))) :mode item :granularity nil :parent #33) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #38) #("the package-name and version, separated by dashes\n" 0 50 (:parent #41))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #24) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #34)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #34)) #(".\n" 0 2 (:parent #34))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #24))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #20) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #25) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #28)) #("\n" 0 1 (:parent #28))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #25) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #29)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #29)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #29)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #29)) #("file.\n" 0 6 (:parent #29))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #25)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #25)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #25) #(" If the package is not available, this would return a " 0 55 (:parent #32)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #32)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #32)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #32)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #32)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #32)) #("below.\n" 0 7 (:parent #32))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #25) #(" #+begin" 0 9 (:parent #33)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #33) #("src" 0 3 (:parent #37))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #33)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #33) #("nar" 0 3 (:parent #39))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #33)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #33) #("pass" 0 4 (:parent #41))) #("\" url \";\")\n \"client" 0 25 (:parent #33)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #33) #("body" 0 4 (:parent #43))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #33) #("buffer" 0 6 (:parent #44))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #33) #("size" 0 4 (:parent #45))) #("256k;\"\n" 0 7 (:parent #33))))))))))
mapconcat(#f(compiled-function (element) #) ((section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) . #0)) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #1)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #1)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #1)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #1)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #1)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #1)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #1)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #1)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #1)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #1)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #1) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #14))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #1) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #15))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #1) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #16))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #1) #("Earlier this year " 0 18 (:parent #17)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #17) #("I announced on the guix mailing list" 0 36 (:parent #21))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #17)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #2))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) . #0)) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #2) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #5) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #8))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #5) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #9) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #12) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #15) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #18) #("Improved Build Diversity" 0 24 (:parent #21)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #15)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #9) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #13) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #16) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #19) #("Reduced Latency" 0 15 (:parent #22)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #16)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #9) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #14) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #17) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #20) #("Increased Resilience" 0 20 (:parent #23)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #17)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #9) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #15) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #18) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #21) #("Community Contribution" 0 22 (:parent #24)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #18))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #5) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #10)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #10) #("here" 0 4 (:parent #14))) #(".\n" 0 2 (:parent #10))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #3))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) . #0)) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #3) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #6) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #9))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #6) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #10) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #13) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #16) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #19) #("Processor" 0 9 (:parent #22)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #16)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #10) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #14) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #17) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #20) #("RAM" 0 3 (:parent #23)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #17)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #10) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #15) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #18) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #21) #("Storage" 0 7 (:parent #24)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #18)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #10) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #16) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #19) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #22) #("Network" 0 7 (:parent #25)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #19)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #10) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #17) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #20) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #23) #("Location" 0 8 (:parent #26)))) #(": Memphis TN\n" 0 13 (:parent #20))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #6) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #11))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #6) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #12))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #6) #("For more details, see the " 0 26 (:parent #13)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #13) #("Specifications section" 0 22 (:parent #17))) #("of the Cuirass Manual.\n" 0 23 (:parent #13))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #6) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #14))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #4))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) . #0)) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #7))) :mode section :granularity nil :parent #4) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #7) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #10) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #13)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #13) #("Guix channels" 0 13 (:parent #17))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #13)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #11))) :mode nil :granularity nil :parent #7) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #11) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #14) #("In order to run Cuirass via the " 0 32 (:parent #17)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #17)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #17)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #17)) #("as a " 0 5 (:parent #17)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #17) #("G-Expression" 0 12 (:parent #25))) #("that will return a list of\n" 0 27 (:parent #17)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #17) #("cuirass specifications" 0 22 (:parent #27))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #17))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #14)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #14) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #19)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #19)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #19)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #19) #("Cuirass specification" 0 21 (:parent #25))) #("\ndocumentation for more details.\n" 0 33 (:parent #19))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #14) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #20)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #20) #("Guix Configuration as a Channel" 0 31 (:parent #24))) #(".\n" 0 2 (:parent #20))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #12))) :mode nil :granularity nil :parent #7) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #12) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #15) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #18)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #18)) #("field of our " 0 13 (:parent #18)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #18)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #18))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #15))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #8))) :mode nil :granularity nil :parent #4) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #8) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #11) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #14)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #14) #("guix publish" 0 12 (:parent #18))) #(", which Guix provides the " 0 26 (:parent #14)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #14) #("guix-publish-service-type" 0 25 (:parent #20))) #(",\nwhich is used in the " 0 23 (:parent #14)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #14)) #("field of " 0 9 (:parent #14)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #14)) #("definition.\n" 0 12 (:parent #14))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #11)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #11) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #16))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #9))) :mode nil :granularity nil :parent #4) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #9) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #12) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #15))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #12) #("To anonymize nginx access logs, the " 0 36 (:parent #16)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #16) #("anonip-service-type" 0 19 (:parent #20))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #16)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #16)) #("is defined.\n" 0 12 (:parent #16))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #12)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #12) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #18))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #12)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #12) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #20)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #20)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #20))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #12)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #12) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #22)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #22)) #("field of our\n" 0 13 (:parent #22)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #22)) #("declaration.\n" 0 13 (:parent #22))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #12)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #10))) :mode nil :granularity nil :parent #4) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #10) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #13) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #16)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #14))) :mode nil :granularity nil :parent #10) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #14) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #17) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #20)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #20) #("letsencrypt" 0 11 (:parent #24))) #("via the " 0 8 (:parent #20)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #20) #("certbot" 0 7 (:parent #26))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #20)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #20) #("certbox-service-type" 0 20 (:parent #28))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #20)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #20)) #("field in our " 0 13 (:parent #20)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #20)) #("configuration.\n" 0 15 (:parent #20))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #17)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #17) #("This service references " 0 24 (:parent #22)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #22)) #(", which we define below. It sends " 0 34 (:parent #22)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #22)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #22))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #17)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #17) #("Next we define a function we will use later in the " 0 51 (:parent #24)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #24) #("Configure Nginx Server Blocks" 0 29 (:parent #28))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #24))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #17)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #15)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #15))) :mode nil :granularity nil :parent #10) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #15) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #18) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #21))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #18)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #18) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #23))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #18) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #24) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #27) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #30)) #("\n" 0 1 (:parent #30))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #27) #(" " 0 2 (:parent #31)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #31)) #("provides a route " 0 17 (:parent #31)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #31)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #31)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #31)) #("command). Given away by the reference to " 0 41 (:parent #31)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #31) #("Nix" 0 3 (:parent #41))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #31)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #31) #("Nix Binary Cache" 0 16 (:parent #43))) #(".\n" 0 2 (:parent #31))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #27) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #32))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #27)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #27) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #34))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #27))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #24) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #28) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #31)) #("\n" 0 1 (:parent #31))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #28) #(" " 0 2 (:parent #32)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #32) #("NAR (Nix Archive Format)" 0 24 (:parent #36))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #32)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #32) #("hello" 0 5 (:parent #38))) #("package.\n" 0 9 (:parent #32))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #28) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #33))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #28)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #28)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #28) #(" The result is composed of a few parts:\n" 0 41 (:parent #36))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #28) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #40))) :mode item :granularity nil :parent #37) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #40) #("the guix store path\n" 0 20 (:parent #43)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #41))) :mode item :granularity nil :parent #37) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #41) #("a hash uniquely identifying the store item\n" 0 43 (:parent #44)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #42))) :mode item :granularity nil :parent #37) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #42) #("the package-name and version, separated by dashes\n" 0 50 (:parent #45))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #28) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #38)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #38)) #(".\n" 0 2 (:parent #38))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #28))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #24) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #29) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #32)) #("\n" 0 1 (:parent #32))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #29) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #33)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #33)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #33)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #33)) #("file.\n" 0 6 (:parent #33))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #29)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #29)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #29) #(" If the package is not available, this would return a " 0 55 (:parent #36)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #36)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #36)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #36)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #36)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #36)) #("below.\n" 0 7 (:parent #36))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #29) #(" #+begin" 0 9 (:parent #37)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #37) #("src" 0 3 (:parent #41))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #37)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #37) #("nar" 0 3 (:parent #43))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #37)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #37) #("pass" 0 4 (:parent #45))) #("\" url \";\")\n \"client" 0 25 (:parent #37)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #37) #("body" 0 4 (:parent #47))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #37) #("buffer" 0 6 (:parent #48))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #37) #("size" 0 4 (:parent #49))) #("256k;\"\n" 0 7 (:parent #37)))))))))) "")
org-export-data((org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #0) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #3)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #3)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #3)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #3)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #3)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #3)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #3)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #3)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #3)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #3)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #3) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #16))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #3) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #17))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #3) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #18))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #3) #("Earlier this year " 0 18 (:parent #19)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #19) #("I announced on the guix mailing list" 0 36 (:parent #23))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #19)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #4))) :mode nil :granularity nil :parent #0) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #4) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #7) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #10))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #7) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #11) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #14) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #17) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #20) #("Improved Build Diversity" 0 24 (:parent #23)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #17)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #11) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #15) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #18) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #21) #("Reduced Latency" 0 15 (:parent #24)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #18)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #11) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #16) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #19) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #22) #("Increased Resilience" 0 20 (:parent #25)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #19)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #11) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #17) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #20) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #23) #("Community Contribution" 0 22 (:parent #26)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #20))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #7) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #12)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #12) #("here" 0 4 (:parent #16))) #(".\n" 0 2 (:parent #12))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #5))) :mode nil :granularity nil :parent #0) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #5) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #8) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #11))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #8) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #12) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #15) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #18) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #21) #("Processor" 0 9 (:parent #24)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #18)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #12) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #16) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #19) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #22) #("RAM" 0 3 (:parent #25)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #19)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #12) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #17) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #20) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #23) #("Storage" 0 7 (:parent #26)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #20)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #12) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #18) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #21) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #24) #("Network" 0 7 (:parent #27)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #21)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #12) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #19) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #22) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #25) #("Location" 0 8 (:parent #28)))) #(": Memphis TN\n" 0 13 (:parent #22))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #8) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #13))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #8) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #14))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #8) #("For more details, see the " 0 26 (:parent #15)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #15) #("Specifications section" 0 22 (:parent #19))) #("of the Cuirass Manual.\n" 0 23 (:parent #15))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #8) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #16))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #6))) :mode nil :granularity nil :parent #0) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #9))) :mode section :granularity nil :parent #6) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #9) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #12) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #15)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #15) #("Guix channels" 0 13 (:parent #19))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #15)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #13))) :mode nil :granularity nil :parent #9) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #13) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #16) #("In order to run Cuirass via the " 0 32 (:parent #19)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #19)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #19)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #19)) #("as a " 0 5 (:parent #19)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #19) #("G-Expression" 0 12 (:parent #27))) #("that will return a list of\n" 0 27 (:parent #19)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #19) #("cuirass specifications" 0 22 (:parent #29))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #19))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #16)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #16) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #21)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #21)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #21)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #21) #("Cuirass specification" 0 21 (:parent #27))) #("\ndocumentation for more details.\n" 0 33 (:parent #21))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #16) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #22)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #22) #("Guix Configuration as a Channel" 0 31 (:parent #26))) #(".\n" 0 2 (:parent #22))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #14))) :mode nil :granularity nil :parent #9) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #14) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #17) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #20)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #20)) #("field of our " 0 13 (:parent #20)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #20)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #20))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #17))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #10))) :mode nil :granularity nil :parent #6) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #10) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #13) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #16)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #16) #("guix publish" 0 12 (:parent #20))) #(", which Guix provides the " 0 26 (:parent #16)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #16) #("guix-publish-service-type" 0 25 (:parent #22))) #(",\nwhich is used in the " 0 23 (:parent #16)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #16)) #("field of " 0 9 (:parent #16)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #16)) #("definition.\n" 0 12 (:parent #16))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #13)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #13) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #18))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #11))) :mode nil :granularity nil :parent #6) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #11) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #14) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #17))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #14) #("To anonymize nginx access logs, the " 0 36 (:parent #18)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #18) #("anonip-service-type" 0 19 (:parent #22))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #18)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #18)) #("is defined.\n" 0 12 (:parent #18))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #14)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #14) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #20))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #14)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #14) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #22)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #22)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #22))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #14)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #14) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #24)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #24)) #("field of our\n" 0 13 (:parent #24)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #24)) #("declaration.\n" 0 13 (:parent #24))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #14)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #12))) :mode nil :granularity nil :parent #6) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #12) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #15) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #18)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #16))) :mode nil :granularity nil :parent #12) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #16) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #19) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #22)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #22) #("letsencrypt" 0 11 (:parent #26))) #("via the " 0 8 (:parent #22)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #22) #("certbot" 0 7 (:parent #28))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #22)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #22) #("certbox-service-type" 0 20 (:parent #30))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #22)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #22)) #("field in our " 0 13 (:parent #22)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #22)) #("configuration.\n" 0 15 (:parent #22))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #19)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #19) #("This service references " 0 24 (:parent #24)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #24)) #(", which we define below. It sends " 0 34 (:parent #24)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #24)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #24))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #19)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #19) #("Next we define a function we will use later in the " 0 51 (:parent #26)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #26) #("Configure Nginx Server Blocks" 0 29 (:parent #30))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #26))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #19)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #17)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #17))) :mode nil :granularity nil :parent #12) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #17) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #20) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #23))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #20)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #20) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #25))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #20) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #26) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #29) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #32)) #("\n" 0 1 (:parent #32))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #29) #(" " 0 2 (:parent #33)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #33)) #("provides a route " 0 17 (:parent #33)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #33)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #33)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #33)) #("command). Given away by the reference to " 0 41 (:parent #33)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #33) #("Nix" 0 3 (:parent #43))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #33)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #33) #("Nix Binary Cache" 0 16 (:parent #45))) #(".\n" 0 2 (:parent #33))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #29) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #34))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #29)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #29) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #36))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #29))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #26) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #30) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #33)) #("\n" 0 1 (:parent #33))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #30) #(" " 0 2 (:parent #34)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #34) #("NAR (Nix Archive Format)" 0 24 (:parent #38))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #34)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #34) #("hello" 0 5 (:parent #40))) #("package.\n" 0 9 (:parent #34))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #30) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #35))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #30)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #30)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #30) #(" The result is composed of a few parts:\n" 0 41 (:parent #38))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #30) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #42))) :mode item :granularity nil :parent #39) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #42) #("the guix store path\n" 0 20 (:parent #45)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #43))) :mode item :granularity nil :parent #39) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #43) #("a hash uniquely identifying the store item\n" 0 43 (:parent #46)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #44))) :mode item :granularity nil :parent #39) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #44) #("the package-name and version, separated by dashes\n" 0 50 (:parent #47))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #30) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #40)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #40)) #(".\n" 0 2 (:parent #40))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #30))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #26) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #31) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #34)) #("\n" 0 1 (:parent #34))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #31) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #35)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #35)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #35)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #35)) #("file.\n" 0 6 (:parent #35))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #31)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #31)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #31) #(" If the package is not available, this would return a " 0 55 (:parent #38)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #38)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #38)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #38)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #38)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #38)) #("below.\n" 0 7 (:parent #38))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #31) #(" #+begin" 0 9 (:parent #39)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #39) #("src" 0 3 (:parent #43))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #39)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #39) #("nar" 0 3 (:parent #45))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #39)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #39) #("pass" 0 4 (:parent #47))) #("\" url \";\")\n \"client" 0 25 (:parent #39)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #39) #("body" 0 4 (:parent #49))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #39) #("buffer" 0 6 (:parent #50))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #39) #("size" 0 4 (:parent #51))) #("256k;\"\n" 0 7 (:parent #39)))))))))) (:export-options (body-only) :back-end #s(org-export-backend :name html :parent nil :transcoders ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :options ((:html-doctype "HTML_DOCTYPE" nil org-html-doctype) (:html-container "HTML_CONTAINER" nil org-html-container-element) (:html-content-class "HTML_CONTENT_CLASS" nil org-html-content-class) (:description "DESCRIPTION" nil nil newline) (:keywords "KEYWORDS" nil nil space) (:html-html5-fancy nil "html5-fancy" org-html-html5-fancy) (:html-link-use-abs-url nil "html-link-use-abs-url" org-html-link-use-abs-url) (:html-link-home "HTML_LINK_HOME" nil org-html-link-home) (:html-link-up "HTML_LINK_UP" nil org-html-link-up) (:html-mathjax "HTML_MATHJAX" nil "" space) (:html-equation-reference-format "HTML_EQUATION_REFERENCE_FORMAT" nil org-html-equation-reference-format t) (:html-postamble nil "html-postamble" org-html-postamble) (:html-preamble nil "html-preamble" org-html-preamble) (:html-head "HTML_HEAD" nil org-html-head newline) (:html-head-extra "HTML_HEAD_EXTRA" nil org-html-head-extra newline) (:subtitle "SUBTITLE" nil nil parse) (:html-head-include-default-style nil "html-style" org-html-head-include-default-style) (:html-head-include-scripts nil "html-scripts" org-html-head-include-scripts) (:html-allow-name-attribute-in-anchors nil nil org-html-allow-name-attribute-in-anchors) (:html-divs nil nil org-html-divs) (:html-checkbox-type nil nil org-html-checkbox-type) (:html-extension nil nil org-html-extension) (:html-footnote-format nil nil org-html-footnote-format) (:html-footnote-separator nil nil org-html-footnote-separator) (:html-footnotes-section nil nil org-html-footnotes-section) (:html-format-drawer-function nil nil org-html-format-drawer-function) (:html-format-headline-function nil nil org-html-format-headline-function) (:html-format-inlinetask-function nil nil org-html-format-inlinetask-function) (:html-home/up-format nil nil org-html-home/up-format) (:html-indent nil nil org-html-indent) (:html-infojs-options nil nil org-html-infojs-options) (:html-infojs-template nil nil org-html-infojs-template) (:html-inline-image-rules nil nil org-html-inline-image-rules) (:html-link-org-files-as-html nil nil org-html-link-org-files-as-html) (:html-mathjax-options nil nil org-html-mathjax-options) (:html-mathjax-template nil nil org-html-mathjax-template) (:html-metadata-timestamp-format nil nil org-html-metadata-timestamp-format) (:html-postamble-format nil nil org-html-postamble-format) (:html-preamble-format nil nil org-html-preamble-format) (:html-prefer-user-labels nil nil org-html-prefer-user-labels) (:html-self-link-headlines nil nil org-html-self-link-headlines) (:html-table-align-individual-fields nil nil org-html-table-align-individual-fields) (:html-table-caption-above nil nil org-html-table-caption-above) (:html-table-data-tags nil nil org-html-table-data-tags) (:html-table-header-tags nil nil org-html-table-header-tags) (:html-table-use-header-tags-for-first-column nil nil org-html-table-use-header-tags-for-first-column) (:html-tag-class-prefix nil nil org-html-tag-class-prefix) (:html-text-markup-alist nil nil org-html-text-markup-alist) (:html-todo-kwd-class-prefix nil nil org-html-todo-kwd-class-prefix) (:html-toplevel-hlevel nil nil org-html-toplevel-hlevel) (:html-use-infojs nil nil org-html-use-infojs) (:html-validation-link nil nil org-html-validation-link) (:html-viewport nil nil org-html-viewport) (:html-inline-images nil nil org-html-inline-images) (:html-table-attributes nil nil org-html-table-default-attributes) (:html-table-row-open-tag nil nil org-html-table-row-open-tag) (:html-table-row-close-tag nil nil org-html-table-row-close-tag) (:html-xml-declaration nil nil org-html-xml-declaration) (:html-wrap-src-lines nil nil org-html-wrap-src-lines) (:html-klipsify-src nil nil org-html-klipsify-src) (:html-klipse-css nil nil org-html-klipse-css) (:html-klipse-js nil nil org-html-klipse-js) (:html-klipse-selection-script nil nil org-html-klipse-selection-script) (:infojs-opt "INFOJS_OPT" nil nil) (:creator "CREATOR" nil org-html-creator-string) (:with-latex nil "tex" org-html-with-latex) (:latex-header "LATEX_HEADER" nil nil newline)) :filters ((:filter-options . org-html-infojs-install-script) (:filter-parse-tree . org-html-image-link-filter) (:filter-final-output . org-html-final-function)) :blocks nil :menu (104 "Export to HTML" ((72 "As HTML buffer" org-html-export-as-html) (104 "As HTML file" org-html-export-to-html) (111 "As HTML file and open" (lambda (a s v b) (if a (org-html-export-to-html t s v b) (org-open-file (org-html-export-to-html nil s v b)))))))) :translate-alist ((bold . org-html-bold) (center-block . org-html-center-block) (clock . org-html-clock) (code . org-html-code) (drawer . org-html-drawer) (dynamic-block . org-html-dynamic-block) (entity . org-html-entity) (example-block . org-html-example-block) (export-block . org-html-export-block) (export-snippet . org-html-export-snippet) (fixed-width . org-html-fixed-width) (footnote-reference . org-html-footnote-reference) (headline . org-html-headline) (horizontal-rule . org-html-horizontal-rule) (inline-src-block . org-html-inline-src-block) (inlinetask . org-html-inlinetask) (inner-template . org-html-inner-template) (italic . org-html-italic) (item . org-html-item) (keyword . org-html-keyword) (latex-environment . org-html-latex-environment) (latex-fragment . org-html-latex-fragment) (line-break . org-html-line-break) (link . org-html-link) (node-property . org-html-node-property) (paragraph . org-html-paragraph) (plain-list . org-html-plain-list) (plain-text . org-html-plain-text) (planning . org-html-planning) (property-drawer . org-html-property-drawer) (quote-block . org-html-quote-block) (radio-target . org-html-radio-target) (section . org-html-section) (special-block . org-html-special-block) (src-block . org-html-src-block) (statistics-cookie . org-html-statistics-cookie) (strike-through . org-html-strike-through) (subscript . org-html-subscript) (superscript . org-html-superscript) (table . org-html-table) (table-cell . org-html-table-cell) (table-row . org-html-table-row) (target . org-html-target) (template . org-html-template) (timestamp . org-html-timestamp) (underline . org-html-underline) (verbatim . org-html-verbatim) (verse-block . org-html-verse-block)) :exported-data # :input-buffer " *temp*" :input-file nil :html-doctype "xhtml-strict" :html-container "div" :html-content-class "content" :description nil :keywords nil :html-html5-fancy nil :html-link-use-abs-url nil :html-link-home "" :html-link-up "" :html-mathjax "" :html-equation-reference-format "\\eqref{%s}" :html-postamble auto :html-preamble t :html-head "" :html-head-extra "" :subtitle nil :html-head-include-default-style t :html-head-include-scripts nil :html-allow-name-attribute-in-anchors nil :html-divs ((preamble "div" "preamble") (content "div" "content") (postamble "div" "postamble")) :html-checkbox-type ascii :html-extension "html" :html-footnote-format "%s" :html-footnote-separator ", " :html-footnotes-section ") :html-format-headline-function org-html-format-headline-default-function :html-format-inlinetask-function org-html-format-inlinetask-default-function :html-home/up-format "" :html-indent nil :html-infojs-options ((path . "https://orgmode.org/org-info.js") (view . "info") (toc . :with-toc) (ftoc . "0") (tdepth . "max") (sdepth . "max") (mouse . "underline") (buttons . "0") (ltoc . "1") (up . :html-link-up) (home . :html-link-home)) :html-infojs-template "\n\n" :html-inline-image-rules (("file" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("http" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)") ("https" . "\\(?:\\.\\(?:gif\\|jp\\(?:e?g\\)\\|png\\|svg\\|webp\\)\\)")) :html-link-org-files-as-html t :html-mathjax-options ((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js") (scale 1.0) (align "center") (font "mathjax-modern") (overflow "overflow") (tags "ams") (indent "0em") (multlinewidth "85%") (tagindent ".8em") (tagside "right")) :html-mathjax-template "\n\n" :html-metadata-timestamp-format "%Y-%m-%d %a %H:%M" :html-postamble-format (("en" " \n" . " ") :html-table-header-tags ("" . " ") :html-table-use-header-tags-for-first-column nil :html-tag-class-prefix "" :html-text-markup-alist ((bold . "%s") (code . "%s") (underline . "%s") (verbatim . "" :html-table-row-close-tag " " :html-xml-declaration (("html" . "") ("php" . "\"; ?>")) :html-wrap-src-lines nil :html-klipsify-src nil :html-klipse-css "https://storage.googleapis.com/app.klipse.tech/css/codemirror.css" :html-klipse-js "https://storage.googleapis.com/app.klipse.tech/plugin_prod/js/klipse_plugin.min.js" :html-klipse-selection-script "window.klipse_settings = {selector_eval_html: '.src-html',\n selector_eval_js: '.src-js',\n selector_eval_python_client: '.src-python',\n selector_eval_scheme: '.src-scheme',\n selector: '.src-clojure',\n selector_eval_ruby: '.src-ruby'};" :infojs-opt nil :creator "Emacs 29.4 (Org mode 9.6.15)" :with-latex t :latex-header "\\usepackage[margin=1.5cm]{geometry}\n\\usepackage{xcolor}\n\\definecolor{link}{HTML}{506060}\n\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :title (#("Setup of a Simple Guix Build Farm and Substitute Server" 0 55 (:parent #148))) :date nil :author (#("Collin J. Doering" 0 17 (:parent #152))) :email "unknown@genenetwork-development" :language "en" :select-tags ("export") :exclude-tags ("noexport") :headline-levels 3 :preserve-breaks nil :section-numbers nil :time-stamp-file t :with-archived-trees headline :with-author t :with-broken-links nil :with-clocks nil :with-creator nil :with-date t :with-drawers (not "LOGBOOK") :with-email nil :with-emphasize t :with-entities t :with-fixed-width t :with-footnotes t :with-inlinetasks t :with-planning nil :with-priority nil :with-properties nil :with-smart-quotes nil :with-special-strings t :with-statistics-cookies t :with-sub-superscript t :with-toc nil :with-tables t :with-tags t :with-tasks t :with-timestamps t :with-title t :with-todo-keywords t :cite-export (basic nil nil) :bibliography nil :filter-body nil :filter-bold nil :filter-babel-call nil :filter-center-block nil :filter-clock nil :filter-code nil :filter-diary-sexp nil :filter-drawer nil :filter-dynamic-block nil :filter-entity nil :filter-example-block nil :filter-export-block nil :filter-export-snippet nil :filter-final-output (org-html-final-function) :filter-fixed-width nil :filter-footnote-definition nil :filter-footnote-reference nil :filter-headline nil :filter-horizontal-rule nil :filter-inline-babel-call nil :filter-inline-src-block nil :filter-inlinetask nil :filter-italic nil :filter-item nil :filter-keyword nil :filter-latex-environment nil :filter-latex-fragment nil :filter-line-break nil :filter-link nil :filter-node-property nil :filter-options (org-html-infojs-install-script) :filter-paragraph nil :filter-parse-tree (org-html-image-link-filter) :filter-plain-list nil :filter-plain-text nil :filter-planning nil :filter-property-drawer nil :filter-quote-block nil :filter-radio-target nil :filter-section nil :filter-special-block nil :filter-src-block nil :filter-statistics-cookie nil :filter-strike-through nil :filter-subscript nil :filter-superscript nil :filter-table nil :filter-table-cell nil :filter-table-row nil :filter-target nil :filter-timestamp nil :filter-underline nil :filter-verbatim nil :filter-verse-block nil :ignore-list nil :parse-tree (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #338) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #341)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #341)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #341)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #341) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #354))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #341) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #355))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #341) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #356))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #341) #("Earlier this year " 0 18 (:parent #357)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #357) #("I announced on the guix mailing list" 0 36 (:parent #361))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #357)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #342))) :mode nil :granularity nil :parent #338) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #342) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #345) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #348))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #345) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #352) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #355) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #358) #("Improved Build Diversity" 0 24 (:parent #361)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #355)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #353) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #356) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #359) #("Reduced Latency" 0 15 (:parent #362)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #356)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #354) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #357) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #360) #("Increased Resilience" 0 20 (:parent #363)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #357)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #349) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #355) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #358) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #361) #("Community Contribution" 0 22 (:parent #364)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #358))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #345) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #350)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #350) #("here" 0 4 (:parent #354))) #(".\n" 0 2 (:parent #350))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #343))) :mode nil :granularity nil :parent #338) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #343) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #346) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #349))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #346) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #353) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #356) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #359) #("Processor" 0 9 (:parent #362)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #356)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #354) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #357) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #360) #("RAM" 0 3 (:parent #363)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #357)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #355) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #358) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #361) #("Storage" 0 7 (:parent #364)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #358)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #356) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #359) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #362) #("Network" 0 7 (:parent #365)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #359)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #350) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #357) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #360) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #363) #("Location" 0 8 (:parent #366)))) #(": Memphis TN\n" 0 13 (:parent #360))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #346) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #351))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #346) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #352))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #346) #("For more details, see the " 0 26 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #353) #("Specifications section" 0 22 (:parent #357))) #("of the Cuirass Manual.\n" 0 23 (:parent #353))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #346) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #354))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #344))) :mode nil :granularity nil :parent #338) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #347))) :mode section :granularity nil :parent #344) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #347) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #350) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #353)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #353) #("Guix channels" 0 13 (:parent #357))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #353)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #351))) :mode nil :granularity nil :parent #347) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #351) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #354) #("In order to run Cuirass via the " 0 32 (:parent #357)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #357)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #357)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #357)) #("as a " 0 5 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #357) #("G-Expression" 0 12 (:parent #365))) #("that will return a list of\n" 0 27 (:parent #357)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #357) #("cuirass specifications" 0 22 (:parent #367))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #357))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #354)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #354) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #359)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #359)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #359)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #359) #("Cuirass specification" 0 21 (:parent #365))) #("\ndocumentation for more details.\n" 0 33 (:parent #359))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #354) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #360)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #360) #("Guix Configuration as a Channel" 0 31 (:parent #364))) #(".\n" 0 2 (:parent #360))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #352))) :mode nil :granularity nil :parent #347) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #352) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #355) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #358)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #358)) #("field of our " 0 13 (:parent #358)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #358)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #355))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #348))) :mode nil :granularity nil :parent #344) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #348) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #351) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #354)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #354) #("guix publish" 0 12 (:parent #358))) #(", which Guix provides the " 0 26 (:parent #354)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #354) #("guix-publish-service-type" 0 25 (:parent #360))) #(",\nwhich is used in the " 0 23 (:parent #354)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #354)) #("field of " 0 9 (:parent #354)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #354)) #("definition.\n" 0 12 (:parent #354))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #351)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #351) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #356))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #349))) :mode nil :granularity nil :parent #344) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #349) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #352) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #355))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #352) #("To anonymize nginx access logs, the " 0 36 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #356) #("anonip-service-type" 0 19 (:parent #360))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #356)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #356)) #("is defined.\n" 0 12 (:parent #356))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #352) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #358))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #352)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #352) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #360)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #360)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #352)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #352) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #362)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #362)) #("field of our\n" 0 13 (:parent #362)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #362)) #("declaration.\n" 0 13 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #352)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #350))) :mode nil :granularity nil :parent #344) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #350) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #353) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #356)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #354) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #357) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #360)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #360) #("letsencrypt" 0 11 (:parent #364))) #("via the " 0 8 (:parent #360)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #360) #("certbot" 0 7 (:parent #366))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #360) #("certbox-service-type" 0 20 (:parent #368))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #360)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #360)) #("field in our " 0 13 (:parent #360)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #360)) #("configuration.\n" 0 15 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #357) #("This service references " 0 24 (:parent #362)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #362)) #(", which we define below. It sends " 0 34 (:parent #362)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #362)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #362))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #357)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #357) #("Next we define a function we will use later in the " 0 51 (:parent #364)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #364) #("Configure Nginx Server Blocks" 0 29 (:parent #368))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #364))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #357)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #355)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #355) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #358) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #358)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #358) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #363))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #358) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #367) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #370)) #("\n" 0 1 (:parent #370))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #367) #(" " 0 2 (:parent #371)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #371)) #("provides a route " 0 17 (:parent #371)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #371)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #371)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #371)) #("command). Given away by the reference to " 0 41 (:parent #371)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #371) #("Nix" 0 3 (:parent #381))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #371)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #371) #("Nix Binary Cache" 0 16 (:parent #383))) #(".\n" 0 2 (:parent #371))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #367) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #372))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #367)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #367) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #374))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #367))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #368) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #371)) #("\n" 0 1 (:parent #371))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #368) #(" " 0 2 (:parent #372)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #372) #("NAR (Nix Archive Format)" 0 24 (:parent #376))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #372)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #372) #("hello" 0 5 (:parent #378))) #("package.\n" 0 9 (:parent #372))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #368) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #368)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #368)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #368) #(" The result is composed of a few parts:\n" 0 41 (:parent #376))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #368) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #380))) :mode item :granularity nil :parent #377) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #380) #("the guix store path\n" 0 20 (:parent #383)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #381))) :mode item :granularity nil :parent #377) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #381) #("a hash uniquely identifying the store item\n" 0 43 (:parent #384)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #382))) :mode item :granularity nil :parent #377) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #382) #("the package-name and version, separated by dashes\n" 0 50 (:parent #385))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #368) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #378)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #378)) #(".\n" 0 2 (:parent #378))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #368))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #364) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #369) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #372)) #("\n" 0 1 (:parent #372))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #369) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #373)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #373)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #373)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #373)) #("file.\n" 0 6 (:parent #373))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #369)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #369)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #369) #(" If the package is not available, this would return a " 0 55 (:parent #376)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #376)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #376)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #376)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #376)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #376)) #("below.\n" 0 7 (:parent #376))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #369) #(" #+begin" 0 9 (:parent #377)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #377) #("src" 0 3 (:parent #381))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #377)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #377) #("nar" 0 3 (:parent #383))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #377)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #377) #("pass" 0 4 (:parent #385))) #("\" url \";\")\n \"client" 0 25 (:parent #377)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #377) #("body" 0 4 (:parent #387))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #377) #("buffer" 0 6 (:parent #388))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #377) #("size" 0 4 (:parent #389))) #("256k;\"\n" 0 7 (:parent #377)))))))))) :headline-offset 0 :headline-numbering nil :id-alist nil :citations nil :internal-references (("org1d65611" headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #350))) :mode section :granularity nil :parent (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #396))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #442) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #445)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #445)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #445)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #445) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #458))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #445) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #459))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #445) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #460))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #445) #("Earlier this year " 0 18 (:parent #461)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #461) #("I announced on the guix mailing list" 0 36 (:parent #465))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #461)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #446))) :mode nil :granularity nil :parent #442) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #446) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #449) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #452))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #449) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #456) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #459) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #462) #("Improved Build Diversity" 0 24 (:parent #465)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #459)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #457) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #460) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #463) #("Reduced Latency" 0 15 (:parent #466)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #460)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #458) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #461) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #464) #("Increased Resilience" 0 20 (:parent #467)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #461)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #453) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #459) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #462) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #465) #("Community Contribution" 0 22 (:parent #468)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #462))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #449) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #454)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #454) #("here" 0 4 (:parent #458))) #(".\n" 0 2 (:parent #454))))) (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #447))) :mode nil :granularity nil :parent #442) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #447) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #450) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #453))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #450) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #457) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #460) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #463) #("Processor" 0 9 (:parent #466)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #460)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #458) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #461) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #464) #("RAM" 0 3 (:parent #467)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #461)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #459) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #462) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #465) #("Storage" 0 7 (:parent #468)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #462)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #460) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #463) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #466) #("Network" 0 7 (:parent #469)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #463)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #454) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #461) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #464) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #467) #("Location" 0 8 (:parent #470)))) #(": Memphis TN\n" 0 13 (:parent #464))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #450) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #455))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #450) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #456))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #450) #("For more details, see the " 0 26 (:parent #457)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #457) #("Specifications section" 0 22 (:parent #461))) #("of the Cuirass Manual.\n" 0 23 (:parent #457))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #450) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #458))))) #396)) #350 (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #400))) :mode nil :granularity nil :parent #396) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #400) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #403) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #406)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #406) #("guix publish" 0 12 (:parent #410))) #(", which Guix provides the " 0 26 (:parent #406)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #406) #("guix-publish-service-type" 0 25 (:parent #412))) #(",\nwhich is used in the " 0 23 (:parent #406)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #406)) #("field of " 0 9 (:parent #406)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #406)) #("definition.\n" 0 12 (:parent #406))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #403)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #403) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #408))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #401))) :mode nil :granularity nil :parent #396) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #401) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #404) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #407))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #404) #("To anonymize nginx access logs, the " 0 36 (:parent #408)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #408) #("anonip-service-type" 0 19 (:parent #412))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #408)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #408)) #("is defined.\n" 0 12 (:parent #408))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #404) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #410))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #404)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #404) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #412)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #412)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #404)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #404) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #414)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #414)) #("field of our\n" 0 13 (:parent #414)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #414)) #("declaration.\n" 0 13 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #404)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #402))) :mode nil :granularity nil :parent #396) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #402) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #405) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #408)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #406))) :mode nil :granularity nil :parent #402) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #406) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #409) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #412)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #412) #("letsencrypt" 0 11 (:parent #416))) #("via the " 0 8 (:parent #412)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #412) #("certbot" 0 7 (:parent #418))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #412)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #412) #("certbox-service-type" 0 20 (:parent #420))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #412)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #412)) #("field in our " 0 13 (:parent #412)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #412)) #("configuration.\n" 0 15 (:parent #412))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #409) #("This service references " 0 24 (:parent #414)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #414)) #(", which we define below. It sends " 0 34 (:parent #414)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #414)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #414))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #409)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #409) #("Next we define a function we will use later in the " 0 51 (:parent #416)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #416) #("Configure Nginx Server Blocks" 0 29 (:parent #420))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #416))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #409)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #407)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #407) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #410) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #413))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #410)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #410) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #415))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #419) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #422)) #("\n" 0 1 (:parent #422))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #419) #(" " 0 2 (:parent #423)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #423)) #("provides a route " 0 17 (:parent #423)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #423)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #423)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #423)) #("command). Given away by the reference to " 0 41 (:parent #423)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #423) #("Nix" 0 3 (:parent #433))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #423)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #423) #("Nix Binary Cache" 0 16 (:parent #435))) #(".\n" 0 2 (:parent #423))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #419) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #424))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #419)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #419) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #419))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #420) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #423)) #("\n" 0 1 (:parent #423))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #420) #(" " 0 2 (:parent #424)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #424) #("NAR (Nix Archive Format)" 0 24 (:parent #428))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #424)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #424) #("hello" 0 5 (:parent #430))) #("package.\n" 0 9 (:parent #424))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #420) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #420)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #420)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #420) #(" The result is composed of a few parts:\n" 0 41 (:parent #428))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #420) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #432))) :mode item :granularity nil :parent #429) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #432) #("the guix store path\n" 0 20 (:parent #435)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #433))) :mode item :granularity nil :parent #429) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #433) #("a hash uniquely identifying the store item\n" 0 43 (:parent #436)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #434))) :mode item :granularity nil :parent #429) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #434) #("the package-name and version, separated by dashes\n" 0 50 (:parent #437))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #420) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #430)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #430)) #(".\n" 0 2 (:parent #430))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #420))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #416) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #421) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #424)) #("\n" 0 1 (:parent #424))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #421) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #425)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #425)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #425)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #425)) #("file.\n" 0 6 (:parent #425))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #421)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #421)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #421) #(" If the package is not available, this would return a " 0 55 (:parent #428)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #428)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #428)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #428)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #428)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #428)) #("below.\n" 0 7 (:parent #428))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #421) #(" #+begin" 0 9 (:parent #429)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #429) #("src" 0 3 (:parent #433))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #429)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #429) #("nar" 0 3 (:parent #435))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #429)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #429) #("pass" 0 4 (:parent #437))) #("\" url \";\")\n \"client" 0 25 (:parent #429)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #429) #("body" 0 4 (:parent #439))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #429) #("buffer" 0 6 (:parent #440))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #429) #("size" 0 4 (:parent #441))) #("256k;\"\n" 0 7 (:parent #429)))))))))) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #350) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #353) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #356)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #356) #("Guix channels" 0 13 (:parent #360))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #356)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #354))) :mode nil :granularity nil :parent #350) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #354) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #357) #("In order to run Cuirass via the " 0 32 (:parent #360)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #360)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #360)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #360)) #("as a " 0 5 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #360) #("G-Expression" 0 12 (:parent #368))) #("that will return a list of\n" 0 27 (:parent #360)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #360) #("cuirass specifications" 0 22 (:parent #370))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #360))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #357)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #357) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #362)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #362)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #362)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #362) #("Cuirass specification" 0 21 (:parent #368))) #("\ndocumentation for more details.\n" 0 33 (:parent #362))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #357) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #363)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #363) #("Guix Configuration as a Channel" 0 31 (:parent #367))) #(".\n" 0 2 (:parent #363))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #355))) :mode nil :granularity nil :parent #350) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #355) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #358) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #361)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #361)) #("field of our " 0 13 (:parent #361)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #361)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #361))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #358))))) ((other "Cuirass" "-" "Building" "Packages") . 30823953) ((headline "Cuirass" "-" "Building" "Packages") . 30823953) ("org46b8c57" headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #353))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #399) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #402)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #402)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #402)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #402) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #415))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #402) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #416))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #402) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #417))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #402) #("Earlier this year " 0 18 (:parent #418)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #418) #("I announced on the guix mailing list" 0 36 (:parent #422))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #418)))) (headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #403))) :mode nil :granularity nil :parent #399) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #403) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #406) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #409))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #406) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #413) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #416) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #419) #("Improved Build Diversity" 0 24 (:parent #422)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #416)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #414) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #417) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #420) #("Reduced Latency" 0 15 (:parent #423)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #417)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #415) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #418) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #421) #("Increased Resilience" 0 20 (:parent #424)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #418)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #410) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #416) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #419) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #422) #("Community Contribution" 0 22 (:parent #425)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #419))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #406) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #411)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #411) #("here" 0 4 (:parent #415))) #(".\n" 0 2 (:parent #411))))) #353 (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #405))) :mode nil :granularity nil :parent #399) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #408))) :mode section :granularity nil :parent #405) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #408) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #411) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #414)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #414) #("Guix channels" 0 13 (:parent #418))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #414)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #412) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #415) #("In order to run Cuirass via the " 0 32 (:parent #418)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #418)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #418)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #418)) #("as a " 0 5 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #418) #("G-Expression" 0 12 (:parent #426))) #("that will return a list of\n" 0 27 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #418) #("cuirass specifications" 0 22 (:parent #428))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #415)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #415) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #420)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #420)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #420) #("Cuirass specification" 0 21 (:parent #426))) #("\ndocumentation for more details.\n" 0 33 (:parent #420))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #415) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #421)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #421) #("Guix Configuration as a Channel" 0 31 (:parent #425))) #(".\n" 0 2 (:parent #421))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #413) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #416) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #419)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #419)) #("field of our " 0 13 (:parent #419)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #419)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #416))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #409))) :mode nil :granularity nil :parent #405) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #409) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #412) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #415)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #415) #("guix publish" 0 12 (:parent #419))) #(", which Guix provides the " 0 26 (:parent #415)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #415) #("guix-publish-service-type" 0 25 (:parent #421))) #(",\nwhich is used in the " 0 23 (:parent #415)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #415)) #("field of " 0 9 (:parent #415)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #415)) #("definition.\n" 0 12 (:parent #415))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #412)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #412) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #417))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #410))) :mode nil :granularity nil :parent #405) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #410) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #413) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #416))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #413) #("To anonymize nginx access logs, the " 0 36 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #417) #("anonip-service-type" 0 19 (:parent #421))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #417)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #417)) #("is defined.\n" 0 12 (:parent #417))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #413) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #419))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #413)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #413) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #421)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #421)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #413)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #413) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #423)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #423)) #("field of our\n" 0 13 (:parent #423)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #423)) #("declaration.\n" 0 13 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #413)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #411))) :mode nil :granularity nil :parent #405) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #411) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #414) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #417)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #415) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #418) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #421)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #421) #("letsencrypt" 0 11 (:parent #425))) #("via the " 0 8 (:parent #421)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #421) #("certbot" 0 7 (:parent #427))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #421) #("certbox-service-type" 0 20 (:parent #429))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #421)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #421)) #("field in our " 0 13 (:parent #421)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #421)) #("configuration.\n" 0 15 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #418) #("This service references " 0 24 (:parent #423)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #423)) #(", which we define below. It sends " 0 34 (:parent #423)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #423)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #423))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #418)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #418) #("Next we define a function we will use later in the " 0 51 (:parent #425)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #425) #("Configure Nginx Server Blocks" 0 29 (:parent #429))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #418)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #416)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #416) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #419) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #419)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #419) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #424))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #419) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #428) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #431)) #("\n" 0 1 (:parent #431))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #428) #(" " 0 2 (:parent #432)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #432)) #("provides a route " 0 17 (:parent #432)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #432)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #432)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #432)) #("command). Given away by the reference to " 0 41 (:parent #432)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #432) #("Nix" 0 3 (:parent #442))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #432)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #432) #("Nix Binary Cache" 0 16 (:parent #444))) #(".\n" 0 2 (:parent #432))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #428) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #433))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #428)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #428) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #435))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #428))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #429) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #432)) #("\n" 0 1 (:parent #432))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #429) #(" " 0 2 (:parent #433)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #433) #("NAR (Nix Archive Format)" 0 24 (:parent #437))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #433)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #433) #("hello" 0 5 (:parent #439))) #("package.\n" 0 9 (:parent #433))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #429) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #429)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #429)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #429) #(" The result is composed of a few parts:\n" 0 41 (:parent #437))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #429) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #441))) :mode item :granularity nil :parent #438) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #441) #("the guix store path\n" 0 20 (:parent #444)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #442))) :mode item :granularity nil :parent #438) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #442) #("a hash uniquely identifying the store item\n" 0 43 (:parent #445)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #443))) :mode item :granularity nil :parent #438) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #443) #("the package-name and version, separated by dashes\n" 0 50 (:parent #446))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #429) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #439)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #439)) #(".\n" 0 2 (:parent #439))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #429))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #425) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #430) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #433)) #("\n" 0 1 (:parent #433))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #430) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #434)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #434)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #434)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #434)) #("file.\n" 0 6 (:parent #434))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #430)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #430)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #430) #(" If the package is not available, this would return a " 0 55 (:parent #437)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #437)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #437)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #437)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #437)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #437)) #("below.\n" 0 7 (:parent #437))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #430) #(" #+begin" 0 9 (:parent #438)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #438) #("src" 0 3 (:parent #442))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #438)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #438) #("nar" 0 3 (:parent #444))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #438)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #438) #("pass" 0 4 (:parent #446))) #("\" url \";\")\n \"client" 0 25 (:parent #438)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #438) #("body" 0 4 (:parent #448))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #438) #("buffer" 0 6 (:parent #449))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #438) #("size" 0 4 (:parent #450))) #("256k;\"\n" 0 7 (:parent #438))))))))))) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #353) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #356) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #359))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #356) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #363) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #366) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #369) #("Processor" 0 9 (:parent #372)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #366)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #364) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #367) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #370) #("RAM" 0 3 (:parent #373)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #367)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #365) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #368) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #371) #("Storage" 0 7 (:parent #374)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #368)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #366) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #369) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #372) #("Network" 0 7 (:parent #375)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #369)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #360) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #367) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #370) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #373) #("Location" 0 8 (:parent #376)))) #(": Memphis TN\n" 0 13 (:parent #370))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #356) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #361))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #356) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #362))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #356) #("For more details, see the " 0 26 (:parent #363)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #363) #("Specifications section" 0 22 (:parent #367))) #("of the Cuirass Manual.\n" 0 23 (:parent #363))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #356) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #364))))) ((other "Hardware" "and" "Infrastructure") . 74157143) ((headline "Hardware" "and" "Infrastructure") . 74157143) ("orgcc40a3d" headline (:raw-value "Why Build Another Substitute Server?" :begin 2009 :end 2958 :pre-blank 1 :contents-begin 2049 :contents-end 2957 :robust-begin 2051 :robust-end 2955 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2009 :title (#("Why Build Another Substitute Server?" 0 36 (:parent #356))) :mode nil :granularity nil :parent (org-data (:begin 1 :contents-begin 1 :contents-end 17864 :end 17864 :robust-begin 3 :robust-end 17862 :post-blank 0 :post-affiliated 1 :path nil :mode org-data :CATEGORY nil :granularity nil) (section (:begin 1 :end 2009 :contents-begin 1 :contents-end 2008 :robust-begin 1 :robust-end 2006 :post-blank 1 :post-affiliated 1 :mode first-section :granularity nil :parent #402) (keyword (:key "TITLE" :value "Setup of a Simple Guix Build Farm and Substitute Server" :begin 1 :end 66 :post-blank 0 :post-affiliated 1 :mode top-comment :granularity nil :parent #405)) (keyword (:key "AUTHOR" :value "Collin J. Doering" :begin 66 :end 95 :post-blank 1 :post-affiliated 66 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage[margin=1.5cm]{geometry}" :begin 95 :end 147 :post-blank 0 :post-affiliated 95 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\usepackage{xcolor}" :begin 147 :end 183 :post-blank 0 :post-affiliated 147 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\definecolor{link}{HTML}{506060}" :begin 183 :end 232 :post-blank 0 :post-affiliated 183 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER" :value "\\hypersetup{colorlinks=true,citecolor=link,filecolor=link,linkcolor=link,urlcolor=link}" :begin 232 :end 337 :post-blank 1 :post-affiliated 232 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\usepackage{mdframed}" :begin 337 :end 381 :post-blank 0 :post-affiliated 337 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\BeforeBeginEnvironment{minted}{\\begin{mdframed}}" :begin 381 :end 453 :post-blank 0 :post-affiliated 381 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX_HEADER_EXTRA" :value "\\AfterEndEnvironment{minted}{\\end{mdframed}}" :begin 453 :end 522 :post-blank 2 :post-affiliated 453 :mode nil :granularity nil :parent #405)) (keyword (:key "LATEX" :value "\\clearpage" :begin 522 :end 543 :post-blank 1 :post-affiliated 522 :mode nil :granularity nil :parent #405)) (paragraph (:begin 543 :end 970 :contents-begin 543 :contents-end 969 :post-blank 1 :post-affiliated 543 :mode nil :granularity nil :parent #405) #("In the world of reproducible computing, GNU Guix stands out as a pioneering distribution that\nenables bit-for-bit reproducible builds and a comprehensive package management system.\nHowever, building software from source for every package can be time-consuming and\nresource-intensive. This is where substitute servers play a crucial role, allowing users to\ndownload pre-built binary packages instead of compiling them locally.\n" 0 426 (:parent #418))) (paragraph (:begin 970 :end 1057 :contents-begin 970 :contents-end 1056 :post-blank 1 :post-affiliated 970 :mode nil :granularity nil :parent #405) #("Here we built a dedicated build farm and substitute server in just few lines of code!\n" 0 86 (:parent #419))) (paragraph (:begin 1057 :end 1512 :contents-begin 1057 :contents-end 1511 :post-blank 1 :post-affiliated 1057 :mode nil :granularity nil :parent #405) #("Guix hands us the programmer's dream of deploying a full server with its services and\norchestration as a program! Not only can the 'program' be adapted to other machines -- across\nthe planet -- the deployment also benefits from Guix reproducibility guarantees, including\nnatural roll-backs of full and partial deployment. The federated nature of these build farms\nis increasingly important - in fact, I invite you to roll-your-own based on this article.\n" 0 454 (:parent #420))) (paragraph (:begin 1512 :end 2008 :contents-begin 1512 :contents-end 2008 :post-blank 0 :post-affiliated 1512 :mode nil :granularity nil :parent #405) #("Earlier this year " 0 18 (:parent #421)) (link (:type "https" :path "//lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :format bracket :raw-link "https://lists.gnu.org/archive/html/guix-devel/2024-07/msg00033.html" :application nil :search-option nil :begin 1530 :end 1640 :contents-begin 1601 :contents-end 1637 :post-blank 1 :parent #421) #("I announced on the guix mailing list" 0 36 (:parent #425))) #("that a new North American based Guix\nsubstitute server and build farm, cuirass.genenetwork.org, was available for general use.\nHaving a server in the USA increases the speed and reduces the latency for North American\ndownloaders of Guix and all 20,000+ built free software packages. It also provides redundancy\nin case something happens with other substitute servers.\n" 0 368 (:parent #421)))) #356 (headline (:raw-value "Hardware and Infrastructure" :begin 2958 :end 4376 :pre-blank 1 :contents-begin 2989 :contents-end 4375 :robust-begin 2991 :robust-end 4373 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 2958 :title (#("Hardware and Infrastructure" 0 27 (:parent #407))) :mode nil :granularity nil :parent #402) (section (:begin 2989 :end 4376 :contents-begin 2989 :contents-end 4375 :robust-begin 2989 :robust-end 4373 :post-blank 1 :post-affiliated 2989 :mode section :granularity nil :parent #407) (paragraph (:begin 2989 :end 3134 :contents-begin 2989 :contents-end 3133 :post-blank 1 :post-affiliated 2989 :mode planning :granularity nil :parent #410) #("The Tennessee Guix Build Farm was made possible through a collaboration with GeneNetwork.org,\nwho provided the following server specifications:\n" 0 144 (:parent #413))) (plain-list (:type unordered :begin 3134 :end 3351 :contents-begin 3134 :contents-end 3350 :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :post-blank 1 :post-affiliated 3134 :mode nil :granularity nil :parent #410) (item (:bullet "- " :begin 3134 :end 3201 :contents-begin 3136 :contents-end 3201 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3134 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3136 :end 3201 :contents-begin 3136 :contents-end 3201 :post-blank 0 :post-affiliated 3136 :mode nil :granularity nil :parent #417) (bold (:begin 3136 :end 3149 :post-blank 0 :contents-begin 3137 :contents-end 3148 :parent #420) (bold (:begin 3137 :end 3148 :post-blank 0 :contents-begin 3138 :contents-end 3147 :parent #423) #("Processor" 0 9 (:parent #426)))) #(": Dual AMD EPYC 9274F 24-Core, 48 Thread Processors\n" 0 52 (:parent #420)))) (item (:bullet "- " :begin 3201 :end 3228 :contents-begin 3203 :contents-end 3228 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3201 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3203 :end 3228 :contents-begin 3203 :contents-end 3228 :post-blank 0 :post-affiliated 3203 :mode nil :granularity nil :parent #418) (bold (:begin 3203 :end 3210 :post-blank 0 :contents-begin 3204 :contents-end 3209 :parent #421) (bold (:begin 3204 :end 3209 :post-blank 0 :contents-begin 3205 :contents-end 3208 :parent #424) #("RAM" 0 3 (:parent #427)))) #(": 768 GB DDR5 ECC\n" 0 18 (:parent #421)))) (item (:bullet "- " :begin 3228 :end 3267 :contents-begin 3230 :contents-end 3267 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3228 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3230 :end 3267 :contents-begin 3230 :contents-end 3267 :post-blank 0 :post-affiliated 3230 :mode nil :granularity nil :parent #419) (bold (:begin 3230 :end 3241 :post-blank 0 :contents-begin 3231 :contents-end 3240 :parent #422) (bold (:begin 3231 :end 3240 :post-blank 0 :contents-begin 3232 :contents-end 3239 :parent #425) #("Storage" 0 7 (:parent #428)))) #(": 1 TB SSD; 2x 3.5 TB HDD\n" 0 26 (:parent #422)))) (item (:bullet "- " :begin 3267 :end 3323 :contents-begin 3269 :contents-end 3323 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3267 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3269 :end 3323 :contents-begin 3269 :contents-end 3323 :post-blank 0 :post-affiliated 3269 :mode nil :granularity nil :parent #420) (bold (:begin 3269 :end 3280 :post-blank 0 :contents-begin 3270 :contents-end 3279 :parent #423) (bold (:begin 3270 :end 3279 :post-blank 0 :contents-begin 3271 :contents-end 3278 :parent #426) #("Network" 0 7 (:parent #429)))) #(": 1 Gbps nic, 100Mbps dedicated connection\n" 0 43 (:parent #423)))) (item (:bullet "- " :begin 3323 :end 3350 :contents-begin 3325 :contents-end 3350 :checkbox nil :counter nil :structure ((3134 0 "- " nil nil nil 3201) (3201 0 "- " nil nil nil 3228) (3228 0 "- " nil nil nil 3267) (3267 0 "- " nil nil nil 3323) (3323 0 "- " nil nil nil 3350)) :pre-blank 0 :post-blank 0 :post-affiliated 3323 :tag nil :mode item :granularity nil :parent #414) (paragraph (:begin 3325 :end 3350 :contents-begin 3325 :contents-end 3350 :post-blank 0 :post-affiliated 3325 :mode nil :granularity nil :parent #421) (bold (:begin 3325 :end 3337 :post-blank 0 :contents-begin 3326 :contents-end 3336 :parent #424) (bold (:begin 3326 :end 3336 :post-blank 0 :contents-begin 3327 :contents-end 3335 :parent #427) #("Location" 0 8 (:parent #430)))) #(": Memphis TN\n" 0 13 (:parent #424))))) (paragraph (:begin 3351 :end 3478 :contents-begin 3351 :contents-end 3477 :post-blank 1 :post-affiliated 3351 :mode nil :granularity nil :parent #410) #("These robust specifications allow for efficient package building, caching, and serving of\nsubstitutes for the Guix community.\n" 0 126 (:parent #415))) (paragraph (:begin 3478 :end 3998 :contents-begin 3478 :contents-end 3997 :post-blank 1 :post-affiliated 3478 :mode nil :granularity nil :parent #410) #("To run your own build farm that builds the entire GNU Guix distribution requires a somewhat\npowerful machine. Namely, in order to keep up with upstream changes we recommend a minimum of\n32GB of RAM, a 8 core CPU, and a 500GB SSD. That being said, Cuirass is flexible, so its also\npossible to build a subset of the distribution and its packages, to better keep up with\npackage builds. Another common use-case is to use Cuirass to build custom channels and\npackages (either in addition to GNU Guix, or a subset thereof).\n" 0 519 (:parent #416))) (paragraph (:begin 3998 :end 4140 :contents-begin 3998 :contents-end 4139 :post-blank 1 :post-affiliated 3998 :mode nil :granularity nil :parent #410) #("For more details, see the " 0 26 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/cuirass.html#Specifications" :application nil :search-option nil :begin 4024 :end 4116 :contents-begin 4091 :contents-end 4113 :post-blank 1 :parent #417) #("Specifications section" 0 22 (:parent #421))) #("of the Cuirass Manual.\n" 0 23 (:parent #417))) (paragraph (:begin 4140 :end 4375 :contents-begin 4140 :contents-end 4375 :post-blank 0 :post-affiliated 4140 :mode nil :granularity nil :parent #410) #("Further measurement and analysis to more precisely determine hardware requirements for\nbuilding GNU Guix and its various packages would be valuable to the Guix community, but we\nhave not yet done such an analysis using our build farm.\n" 0 235 (:parent #418))))) (headline (:raw-value "Components of the Guix Build Farm" :begin 4376 :end 17864 :pre-blank 1 :contents-begin 4413 :contents-end 17864 :robust-begin 4415 :robust-end 17862 :level 1 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4376 :title (#("Components of the Guix Build Farm" 0 33 (:parent #408))) :mode nil :granularity nil :parent #402) (headline (:raw-value "Cuirass - Building Packages" :begin 4413 :end 6692 :pre-blank 1 :contents-begin 4445 :contents-end 6691 :robust-begin 4447 :robust-end 6689 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4413 :title (#("Cuirass - Building Packages" 0 27 (:parent #411))) :mode section :granularity nil :parent #408) (section (:begin 4445 :end 4769 :contents-begin 4445 :contents-end 4768 :robust-begin 4445 :robust-end 4766 :post-blank 1 :post-affiliated 4445 :mode section :granularity nil :parent #411) (paragraph (:begin 4445 :end 4768 :contents-begin 4445 :contents-end 4768 :post-blank 0 :post-affiliated 4445 :mode planning :granularity nil :parent #414) #("Cuirass is the GNU Guix continuous integration software, and is responsible for watching for\nchanges to one or more VCS repositories (usually " 0 142 (:parent #417)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Channels.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Channels.html" :application nil :search-option nil :begin 4587 :end 4660 :contents-begin 4645 :contents-end 4658 :post-blank 0 :parent #417) #("Guix channels" 0 13 (:parent #421))) #("), executing build jobs for\npackages that have changed, and finally, storing build results in its database.\n" 0 108 (:parent #417)))) (headline (:raw-value "Define Cuirass Specs" :begin 4769 :end 6154 :pre-blank 1 :contents-begin 4795 :contents-end 6153 :robust-begin 4797 :robust-end 6151 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 4769 :title (#("Define Cuirass Specs" 0 20 (:parent #415))) :mode nil :granularity nil :parent #411) (section (:begin 4795 :end 6154 :contents-begin 4795 :contents-end 6153 :robust-begin 4795 :robust-end 6151 :post-blank 1 :post-affiliated 4795 :mode section :granularity nil :parent #415) (paragraph (:begin 4795 :end 5284 :contents-begin 4795 :contents-end 5283 :post-blank 1 :post-affiliated 4795 :mode planning :granularity nil :parent #418) #("In order to run Cuirass via the " 0 32 (:parent #421)) (code (:begin 4827 :end 4849 :post-blank 0 :value "cuirass-service-type" :parent #421)) #(", we need to define what we\nwant Cuirass to build. In the case of guix-na, we want to build the GNU Guix distribution and\nits packages, so we declare " 0 150 (:parent #421)) (code (:begin 4999 :end 5016 :post-blank 1 :value "%cuirass-specs" :parent #421)) #("as a " 0 5 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/G_002dExpressions.html" :application nil :search-option nil :begin 5021 :end 5103 :contents-begin 5088 :contents-end 5100 :post-blank 1 :parent #421) #("G-Expression" 0 12 (:parent #429))) #("that will return a list of\n" 0 27 (:parent #421)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5130 :end 5224 :contents-begin 5199 :contents-end 5221 :post-blank 1 :parent #421) #("cuirass specifications" 0 22 (:parent #431))) #("with a single entry named \"guix\", which does exactly that!\n" 0 59 (:parent #421))) (src-block (:language "scheme" :switches nil :parameters nil :begin 5284 :end 5498 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %cuirass-specs\n #~(list (specification\n (name \"guix\")\n (priority 0)\n (build '(channels guix))\n (channels %default-channels))))\n" :post-blank 1 :post-affiliated 5284 :mode nil :granularity nil :parent #418)) (paragraph (:begin 5498 :end 5876 :contents-begin 5498 :contents-end 5875 :post-blank 1 :post-affiliated 5498 :mode nil :granularity nil :parent #418) #("If you have custom channels you wish to build, you would add a new " 0 67 (:parent #423)) (code (:begin 5565 :end 5581 :post-blank 1 :value "specification" :parent #423)) #("to the\nlist. Cuirass can build more then just channels and their packages, it can also build images,\ntarballs, a specific set of packages, a manifest, and more! See the " 0 169 (:parent #423)) (link (:type "https" :path "//guix.gnu.org/cuirass/manual/html_node/Specifications.html" :format bracket :raw-link "https://guix.gnu.org/cuirass/manual/html_node/Specifications.html" :application nil :search-option nil :begin 5750 :end 5842 :contents-begin 5819 :contents-end 5840 :post-blank 0 :parent #423) #("Cuirass specification" 0 21 (:parent #429))) #("\ndocumentation for more details.\n" 0 33 (:parent #423))) (paragraph (:begin 5876 :end 6153 :contents-begin 5876 :contents-end 6153 :post-blank 0 :post-affiliated 5876 :mode nil :granularity nil :parent #418) #("Its worth noting that if you're following along by reviewing the full source code of the\nTennessee build farm that there is an additional specification listed (for guix-na itself!).\nMore details on that in " 0 206 (:parent #424)) (link (:type "fuzzy" :path "*Guix Configuration as a Channel" :format bracket :raw-link "*Guix Configuration as a Channel" :application nil :search-option nil :begin 6082 :end 6151 :contents-begin 6118 :contents-end 6149 :post-blank 0 :parent #424) #("Guix Configuration as a Channel" 0 31 (:parent #428))) #(".\n" 0 2 (:parent #424))))) (headline (:raw-value "Setup Cuirass Service" :begin 6154 :end 6692 :pre-blank 1 :contents-begin 6181 :contents-end 6691 :robust-begin 6183 :robust-end 6689 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6154 :title (#("Setup Cuirass Service" 0 21 (:parent #416))) :mode nil :granularity nil :parent #411) (section (:begin 6181 :end 6692 :contents-begin 6181 :contents-end 6691 :robust-begin 6181 :robust-end 6689 :post-blank 1 :post-affiliated 6181 :mode section :granularity nil :parent #416) (paragraph (:begin 6181 :end 6527 :contents-begin 6181 :contents-end 6526 :post-blank 1 :post-affiliated 6181 :mode planning :granularity nil :parent #419) #("Now that we have defined what we want Cuirass to build, we need to specify its guix service\nin the " 0 99 (:parent #422)) (code (:begin 6280 :end 6291 :post-blank 1 :value "services" :parent #422)) #("field of our " 0 13 (:parent #422)) (code (:begin 6304 :end 6323 :post-blank 1 :value "operating-system" :parent #422)) #("definition, which in turn will run Cuirass.\nWe are going to setup nginx as a reverse proxy for cuirass later on, so we'll set its host to\nlocalhost, and pass along the specifications we defined earlier.\n" 0 203 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 6527 :end 6691 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service cuirass-service-type\n (cuirass-configuration\n (host \"localhost\")\n (specifications %cuirass-specs)))\n" :post-blank 0 :post-affiliated 6527 :mode nil :granularity nil :parent #419))))) (headline (:raw-value "Providing Substitutes using Guix Publish" :begin 6692 :end 7513 :pre-blank 1 :contents-begin 6737 :contents-end 7512 :robust-begin 6739 :robust-end 7510 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 6692 :title (#("Providing Substitutes using Guix Publish" 0 40 (:parent #412))) :mode nil :granularity nil :parent #408) (section (:begin 6737 :end 7513 :contents-begin 6737 :contents-end 7512 :robust-begin 6737 :robust-end 7510 :post-blank 1 :post-affiliated 6737 :mode section :granularity nil :parent #412) (paragraph (:begin 6737 :end 7219 :contents-begin 6737 :contents-end 7218 :post-blank 1 :post-affiliated 6737 :mode planning :granularity nil :parent #415) #("With Cuirass configured and the guix store being populated with package builds as the guix\nchannel changes, we now turn our attention to serving these builds as substitutes to Guix\nusers. This is done using " 0 207 (:parent #418)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Invoking-guix-publish.html" :application nil :search-option nil :begin 6944 :end 7029 :contents-begin 7015 :contents-end 7027 :post-blank 0 :parent #418) #("guix publish" 0 12 (:parent #422))) #(", which Guix provides the " 0 26 (:parent #418)) (link (:type "file" :path "~/.org/roam/20221129213953-advent_of_code.org" :format bracket :raw-link "file:~/.org/roam/20221129213953-advent_of_code.org::*Day 2" :application nil :search-option "*Day 2" :begin 7055 :end 7144 :contents-begin 7117 :contents-end 7142 :post-blank 0 :parent #418) #("guix-publish-service-type" 0 25 (:parent #424))) #(",\nwhich is used in the " 0 23 (:parent #418)) (code (:begin 7167 :end 7178 :post-blank 1 :value "services" :parent #418)) #("field of " 0 9 (:parent #418)) (code (:begin 7187 :end 7206 :post-blank 1 :value "operating-system" :parent #418)) #("definition.\n" 0 12 (:parent #418))) (src-block (:language "scheme" :switches nil :parameters nil :begin 7219 :end 7418 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service guix-publish-service-type\n (guix-publish-configuration\n (port 3000)\n (cache \"/var/cache/guix/publish\")\n (ttl (* 90 24 3600))\n" :post-blank 1 :post-affiliated 7219 :mode nil :granularity nil :parent #415)) (paragraph (:begin 7418 :end 7512 :contents-begin 7418 :contents-end 7512 :post-blank 0 :post-affiliated 7418 :mode nil :granularity nil :parent #415) #("Similar to Cuirass, access to guix-publish will be provided through nginx as a reverse proxy.\n" 0 94 (:parent #420))))) (headline (:raw-value "Anonomizing IPs in logs using anonip" :begin 7513 :end 9563 :pre-blank 1 :contents-begin 7554 :contents-end 9562 :robust-begin 7556 :robust-end 9560 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 7513 :title (#("Anonomizing IPs in logs using anonip" 0 36 (:parent #413))) :mode nil :granularity nil :parent #408) (section (:begin 7554 :end 9563 :contents-begin 7554 :contents-end 9562 :robust-begin 7554 :robust-end 9560 :post-blank 1 :post-affiliated 7554 :mode section :granularity nil :parent #413) (paragraph (:begin 7554 :end 7856 :contents-begin 7554 :contents-end 7855 :post-blank 1 :post-affiliated 7554 :mode planning :granularity nil :parent #416) #("Guix users care about their privacy, and though this is not necessarily a requirement,\nanonymizing nginx access logs using the anonip is implemented by all public Guix sponsored\nbuild farms, so keeping with this privacy preserving trend, cuirass.genenetwork.org\nimplements the same log anonymization.\n" 0 301 (:parent #419))) (paragraph (:begin 7856 :end 8184 :contents-begin 7856 :contents-end 8183 :post-blank 1 :post-affiliated 7856 :mode nil :granularity nil :parent #416) #("To anonymize nginx access logs, the " 0 36 (:parent #420)) (link (:type "https" :path "//guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :format bracket :raw-link "https://guix.gnu.org/manual/devel/en/html_node/Log-Rotation.html" :application nil :search-option nil :begin 7892 :end 7982 :contents-begin 7960 :contents-end 7979 :post-blank 1 :parent #420) #("anonip-service-type" 0 19 (:parent #424))) #("will be configured and used, however, we\nwant to anonymize multiple log files, which means multiple instances of the anonip running.\nTo assist with this, a helper function " 0 172 (:parent #420)) (code (:begin 8154 :end 8171 :post-blank 1 :value "anonip-service" :parent #420)) #("is defined.\n" 0 12 (:parent #420))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8184 :end 8434 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (anonip-service file)\n (service anonip-service-type\n (anonip-configuration\n (input (format #false \"/var/run/anonip/~a\" file))\n (output (format #false \"/var/log/anonip/~a\" file)))\n" :post-blank 1 :post-affiliated 8184 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8434 :end 8735 :contents-begin 8434 :contents-end 8734 :post-blank 1 :post-affiliated 8434 :mode nil :granularity nil :parent #416) #("Additionally, for services that will leverage these anonymized logs (in our case, only\nnginx), it will be necessary to ensure that the appropriate instance of anonip is running\nprior to the respective service that will utilize it. To help declare this dependency,\nanother helper function is defined.\n" 0 300 (:parent #422))) (src-block (:language "scheme" :switches nil :parameters nil :begin 8735 :end 8945 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (log-file->anonip-service-name file)\n \"Return the name of the Anonip service handling FILE, a log file.\"\n (symbol-append 'anonip-/var/log/anonip/ (string->symbol file)))\n" :post-blank 1 :post-affiliated 8735 :mode nil :granularity nil :parent #416)) (paragraph (:begin 8945 :end 9136 :contents-begin 8945 :contents-end 9135 :post-blank 1 :post-affiliated 8945 :mode nil :granularity nil :parent #416) #("We also define a list of anonymized log files which will be used later on along side the\n" 0 89 (:parent #424)) (code (:begin 9034 :end 9066 :post-blank 1 :value "log-file->anonip-service-name" :parent #424)) #("function in order to define shepherd service dependencies for\nnginx.\n" 0 69 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9136 :end 9292 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %anonip-nginx-log-files\n ;; List of files handled by Anonip for nginx\n '(\"http.access.log\"\n \"https.access.log\"))\n" :post-blank 1 :post-affiliated 9136 :mode nil :granularity nil :parent #416)) (paragraph (:begin 9292 :end 9488 :contents-begin 9292 :contents-end 9487 :post-blank 1 :post-affiliated 9292 :mode nil :granularity nil :parent #416) #("All that remains is to ensure that for each log file we are anonymizing, we start a\ncorresponding anonip-service. This can be added to the " 0 139 (:parent #426)) (code (:begin 9431 :end 9442 :post-blank 1 :value "services" :parent #426)) #("field of our\n" 0 13 (:parent #426)) (code (:begin 9455 :end 9474 :post-blank 1 :value "operating-system" :parent #426)) #("declaration.\n" 0 13 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 9488 :end 9562 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(map anonip-service %anonip-nginx-log-files)\n" :post-blank 0 :post-affiliated 9488 :mode nil :granularity nil :parent #416)))) (headline (:raw-value "ProvidIng Web Access - Nginx Reverse Proxy" :begin 9563 :end 17864 :pre-blank 1 :contents-begin 9610 :contents-end 17864 :robust-begin 9612 :robust-end 17862 :level 2 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9563 :title (#("ProvidIng Web Access - Nginx Reverse Proxy" 0 42 (:parent #414))) :mode nil :granularity nil :parent #408) (section (:begin 9610 :end 9798 :contents-begin 9610 :contents-end 9797 :robust-begin 9610 :robust-end 9795 :post-blank 1 :post-affiliated 9610 :mode section :granularity nil :parent #414) (paragraph (:begin 9610 :end 9797 :contents-begin 9610 :contents-end 9797 :post-blank 0 :post-affiliated 9610 :mode planning :granularity nil :parent #417) #("Nginx is arguably the most complicated part of the setup. This section touches on the\nessential details of configuring nginx to act as a reverse proxy for both guix-publish, and\nCuirass.\n" 0 187 (:parent #420)))) (headline (:raw-value "Certbot" :begin 9798 :end 11424 :pre-blank 1 :contents-begin 9811 :contents-end 11423 :robust-begin 9813 :robust-end 11421 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 1 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 9798 :title (#("Certbot" 0 7 (:parent #418))) :mode nil :granularity nil :parent #414) (section (:begin 9811 :end 11424 :contents-begin 9811 :contents-end 11423 :robust-begin 9811 :robust-end 11421 :post-blank 1 :post-affiliated 9811 :mode section :granularity nil :parent #418) (paragraph (:begin 9811 :end 10290 :contents-begin 9811 :contents-end 10289 :post-blank 1 :post-affiliated 9811 :mode planning :granularity nil :parent #421) #("We would like to provide https access to cuirass, so we require a tls certificate, which we\nwill provision using " 0 113 (:parent #424)) (link (:type "https" :path "//letsencrypt.org/" :format bracket :raw-link "https://letsencrypt.org/" :application nil :search-option nil :begin 9924 :end 9966 :contents-begin 9952 :contents-end 9963 :post-blank 1 :parent #424) #("letsencrypt" 0 11 (:parent #428))) #("via the " 0 8 (:parent #424)) (link (:type "https" :path "//github.com/certbot/certbot" :format bracket :raw-link "https://github.com/certbot/certbot" :application nil :search-option nil :begin 9974 :end 10022 :contents-begin 10012 :contents-end 10019 :post-blank 1 :parent #424) #("certbot" 0 7 (:parent #430))) #("tool. Luckily, Guix provides a\n" 0 31 (:parent #424)) (link (:type "https" :path "//guix.gnu.org/manual/en/html_node/Certificate-Services.html" :format bracket :raw-link "https://guix.gnu.org/manual/en/html_node/Certificate-Services.html" :application nil :search-option nil :begin 10053 :end 10146 :contents-begin 10123 :contents-end 10143 :post-blank 1 :parent #424) #("certbox-service-type" 0 20 (:parent #432))) #("which can be used to configure certbot. As with prior services, this is\nadded to our " 0 85 (:parent #424)) (code (:begin 10231 :end 10242 :post-blank 1 :value "services" :parent #424)) #("field in our " 0 13 (:parent #424)) (code (:begin 10255 :end 10274 :post-blank 1 :value "operating-system" :parent #424)) #("configuration.\n" 0 15 (:parent #424))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10290 :end 10605 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(service certbot-service-type\n (certbot-configuration\n (email \"collin@rekahsoft.ca\")\n (certificates\n (list\n (certificate-configuration\n (domains '(\"cuirass.genenetwork.org\"))\n (deploy-hook %nginx-deploy-hook))))))\n" :post-blank 1 :post-affiliated 10290 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10605 :end 10786 :contents-begin 10605 :contents-end 10785 :post-blank 1 :post-affiliated 10605 :mode nil :granularity nil :parent #421) #("This service references " 0 24 (:parent #426)) (code (:begin 10629 :end 10649 :post-blank 0 :value "%nginx-deploy-hook" :parent #426)) #(", which we define below. It sends " 0 34 (:parent #426)) (code (:begin 10683 :end 10692 :post-blank 1 :value "SIGHUP" :parent #426)) #("to\nrestart nginx when certbot renews certificates so the most recent certificate/s are used.\n" 0 93 (:parent #426))) (src-block (:language "scheme" :switches nil :parameters nil :begin 10786 :end 10977 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define %nginx-deploy-hook\n (program-file\n \"nginx-deploy-hook\"\n #~(let ((pid (call-with-input-file \"/var/run/nginx/pid\" read)))\n (kill pid SIGHUP))))\n" :post-blank 1 :post-affiliated 10786 :mode nil :granularity nil :parent #421)) (paragraph (:begin 10977 :end 11210 :contents-begin 10977 :contents-end 11209 :post-blank 1 :post-affiliated 10977 :mode nil :granularity nil :parent #421) #("Next we define a function we will use later in the " 0 51 (:parent #428)) (link (:type "fuzzy" :path "*Configure Nginx Server Blocks" :format bracket :raw-link "*Configure Nginx Server Blocks" :application nil :search-option nil :begin 11028 :end 11094 :contents-begin 11062 :contents-end 11091 :post-blank 1 :parent #428) #("Configure Nginx Server Blocks" 0 29 (:parent #432))) #("section\nto lookup a certificate or private key file by host in order to reference them when\nconfiguring Nginx tls.\n" 0 115 (:parent #428))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11210 :end 11423 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define* (le host #:optional privkey)\n (string-append \"/etc/letsencrypt/live/\"\n host \"/\"\n (if privkey \"privkey\" \"fullchain\")\n \".pem\"))\n" :post-blank 0 :post-affiliated 11210 :mode nil :granularity nil :parent #421)))) (headline (:raw-value "Configure Nginx Location block for ~guix-publish~" :begin 11424 :end 17864 :pre-blank 1 :contents-begin 11479 :contents-end 17864 :robust-begin 11481 :robust-end 17862 :level 3 :priority nil :tags nil :todo-keyword nil :todo-type nil :post-blank 0 :footnote-section-p nil :archivedp nil :commentedp nil :post-affiliated 11424 :title (#("Configure Nginx Location block for " 0 35 (:parent #419)) (code (:begin 11463 :end 11477 :post-blank 0 :value "guix-publish" :parent #419))) :mode nil :granularity nil :parent #414) (section (:begin 11479 :end 17864 :contents-begin 11479 :contents-end 17864 :robust-begin 11479 :robust-end 17862 :post-blank 0 :post-affiliated 11479 :mode section :granularity nil :parent #419) (paragraph (:begin 11479 :end 11627 :contents-begin 11479 :contents-end 11626 :post-blank 1 :post-affiliated 11479 :mode planning :granularity nil :parent #422) #("Lets define a function that given a url, produces a list of appropriate nginx location blocks\nto enable guix-publish running on some provided URL.\n" 0 147 (:parent #425))) (src-block (:language "scheme" :switches nil :parameters nil :begin 11627 :end 11809 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value "(define (publish-locations url)\n \"Return the nginx location blocks for 'guix publish' running on URL.\"\n (list (nginx-location-configuration ...) ...)\n" :post-blank 1 :post-affiliated 11627 :mode nil :granularity nil :parent #422)) (paragraph (:begin 11809 :end 11973 :contents-begin 11809 :contents-end 11972 :post-blank 1 :post-affiliated 11809 :mode nil :granularity nil :parent #422) #("Starting from the definition above, lets fill in and explain the purpose of each\nnginx-location-configuration in the list that will be returned from our function.\n" 0 163 (:parent #427))) (plain-list (:type unordered :begin 11973 :end 17864 :contents-begin 11973 :contents-end 17864 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 0 :post-affiliated 11973 :mode nil :granularity nil :parent #422) (item (:bullet "- " :begin 11973 :end 13477 :contents-begin 11975 :contents-end 13476 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 11973 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 11975 :end 11994 :contents-begin 11975 :contents-end 11993 :post-blank 1 :post-affiliated 11975 :mode nil :granularity nil :parent #431) (code (:begin 11975 :end 11992 :post-blank 0 :value "/nix-cache-info" :parent #434)) #("\n" 0 1 (:parent #434))) (paragraph (:begin 11994 :end 12426 :contents-begin 11994 :contents-end 12425 :post-blank 1 :post-affiliated 11994 :mode nil :granularity nil :parent #431) #(" " 0 2 (:parent #435)) (code (:begin 11996 :end 12011 :post-blank 1 :value "guix-publish" :parent #435)) #("provides a route " 0 17 (:parent #435)) (code (:begin 12028 :end 12046 :post-blank 1 :value "/nix-cache-info" :parent #435)) #("which returns text/plain content of\n key/value pairs, used by cooperating clients (which is normally the case, when using the\n " 0 129 (:parent #435)) (code (:begin 12175 :end 12186 :post-blank 1 :value "guix ..." :parent #435)) #("command). Given away by the reference to " 0 41 (:parent #435)) (link (:type "https" :path "//nixos.org/" :format bracket :raw-link "https://nixos.org/" :application nil :search-option nil :begin 12227 :end 12255 :contents-begin 12249 :contents-end 12252 :post-blank 1 :parent #435) #("Nix" 0 3 (:parent #445))) #("in its name, this route (and some\n aspects of the design of guix-publish) are inspired by nix-serve, and the " 0 110 (:parent #435)) (link (:type "https" :path "//nixos.wiki/wiki/Binary_Cache" :format bracket :raw-link "https://nixos.wiki/wiki/Binary_Cache" :application nil :search-option nil :begin 12365 :end 12423 :contents-begin 12405 :contents-end 12421 :post-blank 0 :parent #435) #("Nix Binary Cache" 0 16 (:parent #447))) #(".\n" 0 2 (:parent #435))) (paragraph (:begin 12426 :end 12613 :contents-begin 12426 :contents-end 12612 :post-blank 1 :post-affiliated 12426 :mode nil :granularity nil :parent #431) #(" At the time of writing this article, the following is returned from\n cuirass.genenetwork.org/nix-cache-info, and will be returned from every guix-published\n based substitute server.\n" 0 186 (:parent #436))) (src-block (:language "text" :switches nil :parameters nil :begin 12613 :end 12703 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " StoreDir: /gnu/store\n WantMassQuery: 0\n Priority: 100\n" :post-blank 1 :post-affiliated 12613 :mode nil :granularity nil :parent #431)) (paragraph (:begin 12703 :end 12846 :contents-begin 12703 :contents-end 12845 :post-blank 1 :post-affiliated 12703 :mode nil :granularity nil :parent #431) #(" Now that we have some more context on the route, here is the nginx-location-configuration\n we will return to proxy requests appropriately.\n" 0 142 (:parent #438))) (src-block (:language "scheme" :switches nil :parameters nil :begin 12846 :end 13476 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"/nix-cache-info\")\n (body\n (list\n (string-append\n \"proxy_pass \" url \"/nix-cache-info;\")\n ;; Cache this file since that's always the first thing we ask\n ;; for.\n \"proxy_cache static;\"\n \"proxy_cache_valid 200 100d;\" ; cache hits for a looong time.\n \"proxy_cache_valid any 5m;\" ; cache misses/others for 5 min.\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 12846 :mode nil :granularity nil :parent #431))) (item (:bullet "- " :begin 13477 :end 15749 :contents-begin 13479 :contents-end 15748 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 1 :post-affiliated 13477 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 13479 :end 13496 :contents-begin 13479 :contents-end 13495 :post-blank 1 :post-affiliated 13479 :mode nil :granularity nil :parent #432) (code (:begin 13479 :end 13494 :post-blank 0 :value "~ \\\\.narinfo$" :parent #435)) #("\n" 0 1 (:parent #435))) (paragraph (:begin 13496 :end 13845 :contents-begin 13496 :contents-end 13844 :post-blank 1 :post-affiliated 13496 :mode nil :granularity nil :parent #432) #(" " 0 2 (:parent #436)) (link (:type "https" :path "//nix.dev/manual/nix/2.22/protocols/nix-archive" :format bracket :raw-link "https://nix.dev/manual/nix/2.22/protocols/nix-archive" :application nil :search-option nil :begin 13498 :end 13582 :contents-begin 13555 :contents-end 13579 :post-blank 1 :parent #436) #("NAR (Nix Archive Format)" 0 24 (:parent #440))) #("is the format used by Guix for cached substitutes. To get a sense\n for how substitutes are downloaded from a guix-publish substitute server, lets take a\n moment to do so manually for the " 0 189 (:parent #436)) (link (:type "https" :path "//packages.guix.gnu.org/packages/hello/2.12.1/" :format bracket :raw-link "https://packages.guix.gnu.org/packages/hello/2.12.1/" :application nil :search-option nil :begin 13771 :end 13835 :contents-begin 13827 :contents-end 13832 :post-blank 1 :parent #436) #("hello" 0 5 (:parent #442))) #("package.\n" 0 9 (:parent #436))) (paragraph (:begin 13845 :end 13931 :contents-begin 13845 :contents-end 13930 :post-blank 1 :post-affiliated 13845 :mode nil :granularity nil :parent #432) #(" First, lets find the store path of the package (but without actually building it).\n" 0 85 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 13931 :end 13993 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " guix build --dry-run hello\n" :post-blank 1 :post-affiliated 13931 :mode nil :granularity nil :parent #432)) (src-block (:language "text" :switches nil :parameters nil :begin 13993 :end 14097 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n" :post-blank 1 :post-affiliated 14006 :results ("") :mode nil :granularity nil :parent #432)) (paragraph (:begin 14097 :end 14139 :contents-begin 14097 :contents-end 14138 :post-blank 1 :post-affiliated 14097 :mode nil :granularity nil :parent #432) #(" The result is composed of a few parts:\n" 0 41 (:parent #440))) (plain-list (:type descriptive :begin 14139 :end 14339 :contents-begin 14139 :contents-end 14338 :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :post-blank 1 :post-affiliated 14139 :mode nil :granularity nil :parent #432) (item (:bullet "- " :begin 14139 :end 14180 :contents-begin 14160 :contents-end 14180 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14139 :tag ((code (:begin 14143 :end 14156 :post-blank 0 :value "/gnu/store/" :parent #444))) :mode item :granularity nil :parent #441) (paragraph (:begin 14160 :end 14180 :contents-begin 14160 :contents-end 14180 :post-blank 0 :post-affiliated 14160 :mode nil :granularity nil :parent #444) #("the guix store path\n" 0 20 (:parent #447)))) (item (:bullet "- " :begin 14180 :end 14265 :contents-begin 14222 :contents-end 14265 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14180 :tag ((code (:begin 14184 :end 14218 :post-blank 0 :value "8bjy9g0cssjrw9ljz2r8ww1sma95isfj" :parent #445))) :mode item :granularity nil :parent #441) (paragraph (:begin 14222 :end 14265 :contents-begin 14222 :contents-end 14265 :post-blank 0 :post-affiliated 14222 :mode nil :granularity nil :parent #445) #("a hash uniquely identifying the store item\n" 0 43 (:parent #448)))) (item (:bullet "- " :begin 14265 :end 14338 :contents-begin 14288 :contents-end 14338 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 14265 :tag ((code (:begin 14269 :end 14284 :post-blank 0 :value "-hello-2.12.1" :parent #446))) :mode item :granularity nil :parent #441) (paragraph (:begin 14288 :end 14338 :contents-begin 14288 :contents-end 14338 :post-blank 0 :post-affiliated 14288 :mode nil :granularity nil :parent #446) #("the package-name and version, separated by dashes\n" 0 50 (:parent #449))))) (paragraph (:begin 14339 :end 14432 :contents-begin 14339 :contents-end 14431 :post-blank 1 :post-affiliated 14339 :mode nil :granularity nil :parent #432) #(" We now have enough context to define our route matching anything that ends in " 0 80 (:parent #442)) (code (:begin 14419 :end 14429 :post-blank 0 :value ".narinfo" :parent #442)) #(".\n" 0 2 (:parent #442))) (src-block (:language "scheme" :switches nil :parameters nil :begin 14432 :end 15748 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " (nginx-location-configuration\n (uri \"~ \\\\.narinfo$\")\n (body\n (list\n ;; Since 'guix publish' has its own caching, and since it relies\n ;; on the atime of cached narinfos to determine whether a\n ;; narinfo can be removed from the cache, don't do any caching\n ;; here.\n (string-append \"proxy_pass \" url \";\")\n\n ;; For HTTP pipelining. This has a dramatic impact on\n ;; performance.\n \"client_body_buffer_size 128k;\"\n\n ;; Narinfos requests are short, serve many of them on a\n ;; connection.\n \"keepalive_requests 600;\"\n\n ;; Do not tolerate slowness of hydra.gnu.org when fetching\n ;; narinfos: better return 504 quickly than wait forever.\n \"proxy_connect_timeout 10s;\"\n \"proxy_read_timeout 10s;\"\n \"proxy_send_timeout 10s;\"\n\n ;; 'guix publish --ttl' produces a 'Cache-Control' header for\n ;; use by 'guix substitute'. Let it through rather than use\n ;; nginx's \"expire\" directive since the expiration time defined\n ;; by 'guix publish' is the right one.\n \"proxy_pass_header Cache-Control;\"\n\n \"proxy_ignore_client_abort on;\"\n\n ;; We need to hide and ignore the Set-Cookie header to enable\n ;; caching.\n \"proxy_hide_header Set-Cookie;\"\n \"proxy_ignore_headers Set-Cookie;\")))\n" :post-blank 0 :post-affiliated 14432 :mode nil :granularity nil :parent #432))) (item (:bullet "- " :begin 15749 :end 17864 :contents-begin 15751 :contents-end 17864 :checkbox nil :counter nil :structure ((11973 0 "- " nil nil nil 13477) (13477 0 "- " nil nil nil 15749) (14139 2 "- " nil nil "~/gnu/store/~" 14180) (14180 2 "- " nil nil "~8bjy9g0cssjrw9ljz2r8ww1sma95isfj~" 14265) (14265 2 "- " nil nil "~-hello-2.12.1~" 14338) (15749 0 "- " nil nil nil 17864)) :pre-blank 0 :post-blank 0 :post-affiliated 15749 :tag nil :mode item :granularity nil :parent #428) (paragraph (:begin 15751 :end 15760 :contents-begin 15751 :contents-end 15759 :post-blank 1 :post-affiliated 15751 :mode nil :granularity nil :parent #433) (code (:begin 15751 :end 15758 :post-blank 0 :value "/nar/" :parent #436)) #("\n" 0 1 (:parent #436))) (paragraph (:begin 15760 :end 16011 :contents-begin 15760 :contents-end 16010 :post-blank 1 :post-affiliated 15760 :mode nil :granularity nil :parent #433) #(" As part of defining the nginx-location-configuration for " 0 59 (:parent #437)) (code (:begin 15819 :end 15831 :post-blank 1 :value "*.narinfo" :parent #437)) #("routes, we started to\n manually fetch a substitute. Here we will continue, using the provided hash to query to\n query the substitute server for a corresponding " 0 162 (:parent #437)) (code (:begin 15993 :end 16004 :post-blank 1 :value ".narinfo" :parent #437)) #("file.\n" 0 6 (:parent #437))) (src-block (:language "shell" :switches nil :parameters nil :begin 16011 :end 16124 :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :value " curl https://cuirass.genenetwork.org/8bjy9g0cssjrw9ljz2r8ww1sma95isfj.narinfo\n" :post-blank 1 :post-affiliated 16011 :mode nil :granularity nil :parent #433)) (example-block (:begin 16124 :end 17343 :value " StorePath: /gnu/store/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n NarHash: sha256:0f94l0bl09i2igkhklzkawqbbdn4kkxl90wbb4y7f0dnni4f6ljh\n NarSize: 235240\n References: 8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1 zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39 zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib\n Deriver: 79dhya6sngg4rf53m1cyxlhn8y4pnw2n-hello-2.12.1.drv\n Signature: 1;balg02;KHNpZ25hdHVyZSAKIChkYXRhIAogIChmbGFncyByZmM2OTc5KQogIChoYXNoIHNoYTI1NiAjNjE0ODFDNDUzMkU3RTIyOUEzMDlDREVBRDM2MkE2Qzk4QjU0RkFDNEUyQjA1ODEzQ0ZDOEI1NzQ2RUY0NjYxMiMpCiAgKQogKHNpZy12YWwgCiAgKGVjZHNhIAogICAociAjMDQ2NTA3Q0FBNUJFNEY1QUQxRUE0NzUwQzlEMjgzMjQ5NDMwMDQ1OEIzRTM5QUJDOTBFMjZGNkU0MTA0RjMwNCMpCiAgIChzICMwQjdERDlCRUE5ODA0MTkyQ0E2OTUwQzFGRUYzRDdEQ0M3RTMyQzNEMENGNDg3NkY4RkRBMzEwRTUzNkYwNEVBIykKICAgKQogICkKIChwdWJsaWMta2V5IAogIChlY2MgCiAgIChjdXJ2ZSBFZDI1NTE5KQogICAocSAjOTU3OEFENkNEQjIzQkE1MUY5QzQxODVENUQ1QTMyQTdFRUI0N0FDREQ1NUYxQ0NCOENFRTRFMDU3MEZCRjk2MSMpCiAgICkKICApCiApCg==\n URL: nar/gzip/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: gzip\n FileSize: 73331\n URL: nar/zstd/8bjy9g0cssjrw9ljz2r8ww1sma95isfj-hello-2.12.1\n Compression: zstd\n FileSize: 65480\n" :switches nil :number-lines nil :preserve-indent nil :retain-labels t :use-labels t :label-fmt nil :post-blank 1 :post-affiliated 16137 :results ("") :mode nil :granularity nil :parent #433)) (paragraph (:begin 17343 :end 17683 :contents-begin 17343 :contents-end 17682 :post-blank 1 :post-affiliated 17343 :mode nil :granularity nil :parent #433) #(" If the package is not available, this would return a " 0 55 (:parent #440)) (code (:begin 17398 :end 17404 :post-blank 1 :value "404" :parent #440)) #("not found error. However, in our\n case the substitute is found, and various details about it are provided back to the\n requester. The " 0 136 (:parent #440)) (code (:begin 17540 :end 17546 :post-blank 1 :value "URL" :parent #440)) #("field is notable, as it will be used next to download the substitute,\n which is why we define another proxied route for " 0 121 (:parent #440)) (code (:begin 17667 :end 17675 :post-blank 1 :value "/nar/" :parent #440)) #("below.\n" 0 7 (:parent #440))) (paragraph (:begin 17683 :end 17864 :contents-begin 17683 :contents-end 17864 :post-blank 0 :post-affiliated 17683 :mode nil :granularity nil :parent #433) #(" #+begin" 0 9 (:parent #441)) (subscript (:begin 17692 :end 17697 :use-brackets-p nil :contents-begin 17693 :contents-end 17696 :post-blank 1 :parent #441) #("src" 0 3 (:parent #445))) #("scheme\n (nginx-location-configuration\n (uri \"" 0 52 (:parent #441)) (italic (:begin 17749 :end 17754 :post-blank 0 :contents-begin 17750 :contents-end 17753 :parent #441) #("nar" 0 3 (:parent #447))) #("\")\n (body\n (list\n (string-append \"proxy" 0 54 (:parent #441)) (subscript (:begin 17808 :end 17814 :use-brackets-p nil :contents-begin 17809 :contents-end 17813 :post-blank 1 :parent #441) #("pass" 0 4 (:parent #449))) #("\" url \";\")\n \"client" 0 25 (:parent #441)) (subscript (:begin 17839 :end 17844 :use-brackets-p nil :contents-begin 17840 :contents-end 17844 :post-blank 0 :parent #441) #("body" 0 4 (:parent #451))) (subscript (:begin 17844 :end 17851 :use-brackets-p nil :contents-begin 17845 :contents-end 17851 :post-blank 0 :parent #441) #("buffer" 0 6 (:parent #452))) (subscript (:begin 17851 :end 17857 :use-brackets-p nil :contents-begin 17852 :contents-end 17856 :post-blank 1 :parent #441) #("size" 0 4 (:parent #453))) #("256k;\"\n" 0 7 (:parent #441))))))))))) (section (:begin 2049 :end 2958 :contents-begin 2049 :contents-end 2957 :robust-begin 2049 :robust-end 2955 :post-blank 1 :post-affiliated 2049 :mode section :granularity nil :parent #356) (paragraph (:begin 2049 :end 2199 :contents-begin 2049 :contents-end 2198 :post-blank 1 :post-affiliated 2049 :mode planning :granularity nil :parent #359) #("The Guix ecosystem thrives on diversity and decentralization. By establishing additional\nsubstitute servers, we achieve several critical objectives:\n" 0 149 (:parent #362))) (plain-list (:type unordered :begin 2199 :end 2690 :contents-begin 2199 :contents-end 2689 :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :post-blank 1 :post-affiliated 2199 :mode nil :granularity nil :parent #359) (item (:bullet "- " :begin 2199 :end 2365 :contents-begin 2201 :contents-end 2365 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2199 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2201 :end 2365 :contents-begin 2201 :contents-end 2365 :post-blank 0 :post-affiliated 2201 :mode nil :granularity nil :parent #366) (bold (:begin 2201 :end 2229 :post-blank 0 :contents-begin 2202 :contents-end 2228 :parent #369) (bold (:begin 2202 :end 2228 :post-blank 0 :contents-begin 2203 :contents-end 2227 :parent #372) #("Improved Build Diversity" 0 24 (:parent #375)))) #(": Multiple independent build farms reduce the risk of\nsingle-point-of-failure and increase the verification of build reproducibility.\n" 0 134 (:parent #369)))) (item (:bullet "- " :begin 2365 :end 2484 :contents-begin 2367 :contents-end 2484 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2365 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2367 :end 2484 :contents-begin 2367 :contents-end 2484 :post-blank 0 :post-affiliated 2367 :mode nil :granularity nil :parent #367) (bold (:begin 2367 :end 2386 :post-blank 0 :contents-begin 2368 :contents-end 2385 :parent #370) (bold (:begin 2368 :end 2385 :post-blank 0 :contents-begin 2369 :contents-end 2384 :parent #373) #("Reduced Latency" 0 15 (:parent #376)))) #(": Geographically distributed servers mean faster download times for\nusers in different regions.\n" 0 96 (:parent #370)))) (item (:bullet "- " :begin 2484 :end 2585 :contents-begin 2486 :contents-end 2585 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2484 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2486 :end 2585 :contents-begin 2486 :contents-end 2585 :post-blank 0 :post-affiliated 2486 :mode nil :granularity nil :parent #368) (bold (:begin 2486 :end 2510 :post-blank 0 :contents-begin 2487 :contents-end 2509 :parent #371) (bold (:begin 2487 :end 2509 :post-blank 0 :contents-begin 2488 :contents-end 2508 :parent #374) #("Increased Resilience" 0 20 (:parent #377)))) #(": If one substitute server is down, users can fall back to\nalternatives.\n" 0 73 (:parent #371)))) (item (:bullet "- " :begin 2585 :end 2689 :contents-begin 2587 :contents-end 2689 :checkbox nil :counter nil :structure ((2199 0 "- " nil nil nil 2365) (2365 0 "- " nil nil nil 2484) (2484 0 "- " nil nil nil 2585) (2585 0 "- " nil nil nil 2689)) :pre-blank 0 :post-blank 0 :post-affiliated 2585 :tag nil :mode item :granularity nil :parent #363) (paragraph (:begin 2587 :end 2689 :contents-begin 2587 :contents-end 2689 :post-blank 0 :post-affiliated 2587 :mode nil :granularity nil :parent #369) (bold (:begin 2587 :end 2613 :post-blank 0 :contents-begin 2588 :contents-end 2612 :parent #372) (bold (:begin 2588 :end 2612 :post-blank 0 :contents-begin 2589 :contents-end 2611 :parent #375) #("Community Contribution" 0 22 (:parent #378)))) #(": Each new substitute server strengthens the broader Guix\ninfrastructure.\n" 0 74 (:parent #372))))) (paragraph (:begin 2690 :end 2957 :contents-begin 2690 :contents-end 2957 :post-blank 0 :post-affiliated 2690 :mode nil :granularity nil :parent #359) #("This article provides a comprehensive guide to setting up a Guix build farm and substitute\nserver, drawing inspiration from existing GNU Guix project infrastructure. You can see their\nfull source code " 0 201 (:parent #364)) (link (:type "https" :path "//git.savannah.gnu.org/cgit/guix/maintenance.git" :format bracket :raw-link "https://git.savannah.gnu.org/cgit/guix/maintenance.git" :application nil :search-option nil :begin 2891 :end 2955 :contents-begin 2949 :contents-end 2953 :post-blank 0 :parent #364) #("here" 0 4 (:parent #368))) #(".\n" 0 2 (:parent #364))))) ((other "Why" "Build" "Another" "Substitute" "Server?") . 214174269) ((headline "Why" "Build" "Another" "Substitute" "Server?") . 214174269)) :resolve-fuzzy-link-cache #))
org-export-as(html nil nil t nil)
org-export-to-buffer(html "*Org HTML Export*" nil nil nil t nil #f(compiled-function () #))
org-html-export-as-html(nil nil nil t)
(progn (pipe-stdin-into-current-buffer) (org-html-export-as-html nil nil nil t) (princ (buffer-string)))
(unwind-protect (progn (pipe-stdin-into-current-buffer) (org-html-export-as-html nil nil nil t) (princ (buffer-string))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (pipe-stdin-into-current-buffer) (org-html-export-as-html nil nil nil t) (princ (buffer-string))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer))))
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (pipe-stdin-into-current-buffer) (org-html-export-as-html nil nil nil t) (princ (buffer-string))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
eval-buffer(# nil "/gnu/store/0h55qvzlzmvwgigk6nrzcc6s2g30ddm0-org2html.el" nil t)
#f(compiled-function (buffer file) #)(# "/gnu/store/0h55qvzlzmvwgigk6nrzcc6s2g30ddm0-org2html.el")
load-with-code-conversion("/gnu/store/0h55qvzlzmvwgigk6nrzcc6s2g30ddm0-org2html.el" "/gnu/store/0h55qvzlzmvwgigk6nrzcc6s2g30ddm0-org2html.el" nil t #f(compiled-function (buffer file) #))
command-line--load-script("/gnu/store/0h55qvzlzmvwgigk6nrzcc6s2g30ddm0-org2html.el")
command-line-1(("-scriptload" "/gnu/store/0h55qvzlzmvwgigk6nrzcc6s2g30ddm0-org2html.el"))
command-line()
normal-top-level()
\n
" :html-format-drawer-function #f(compiled-function (name contents) #%s:
\n\n%s\n
\nDate: %d
\n%c
\n%v
")) :html-preamble-format (("en" "")) :html-prefer-user-labels nil :html-self-link-headlines nil :html-table-align-individual-fields t :html-table-caption-above t :html-table-data-tags ("%s
") (italic . "%s") (strike-through . "%s
")) :html-todo-kwd-class-prefix "" :html-toplevel-hlevel 2 :html-use-infojs when-configured :html-validation-link "Validate" :html-viewport ((width "device-width") (initial-scale "1") (minimum-scale "") (maximum-scale "") (user-scalable "")) :html-inline-images t :html-table-attributes (:border "2" :cellspacing "0" :cellpadding "6" :rules "groups" :frame "hsides") :html-table-row-open-tag "\n
" :html-format-drawer-function #f(compiled-function (name contents) #%s:
\n\n%s\n
\nDate: %d
\n%c
\n%v
")) :html-preamble-format (("en" "")) :html-prefer-user-labels nil :html-self-link-headlines nil :html-table-align-individual-fields t :html-table-caption-above t :html-table-data-tags ("%s
") (italic . "%s") (strike-through . "%s
")) :html-todo-kwd-class-prefix "" :html-toplevel-hlevel 2 :html-use-infojs when-configured :html-validation-link "Validate" :html-viewport ((width "device-width") (initial-scale "1") (minimum-scale "") (maximum-scale "") (user-scalable "")) :html-inline-images t :html-table-attributes (:border "2" :cellspacing "0" :cellpadding "6" :rules "groups" :frame "hsides") :html-table-row-open-tag "\n
" :html-format-drawer-function #f(compiled-function (name contents) #%s:
\n\n%s\n
\nDate: %d
\n%c
\n%v
")) :html-preamble-format (("en" "")) :html-prefer-user-labels nil :html-self-link-headlines nil :html-table-align-individual-fields t :html-table-caption-above t :html-table-data-tags ("%s
") (italic . "%s") (strike-through . "%s
")) :html-todo-kwd-class-prefix "" :html-toplevel-hlevel 2 :html-use-infojs when-configured :html-validation-link "Validate" :html-viewport ((width "device-width") (initial-scale "1") (minimum-scale "") (maximum-scale "") (user-scalable "")) :html-inline-images t :html-table-attributes (:border "2" :cellspacing "0" :cellpadding "6" :rules "groups" :frame "hsides") :html-table-row-open-tag "\n
" :html-format-drawer-function #f(compiled-function (name contents) #%s:
\n\n%s\n
\nDate: %d
\n%c
\n%v
")) :html-preamble-format (("en" "")) :html-prefer-user-labels nil :html-self-link-headlines nil :html-table-align-individual-fields t :html-table-caption-above t :html-table-data-tags ("%s
") (italic . "%s") (strike-through . "%s
")) :html-todo-kwd-class-prefix "" :html-toplevel-hlevel 2 :html-use-infojs when-configured :html-validation-link "Validate" :html-viewport ((width "device-width") (initial-scale "1") (minimum-scale "") (maximum-scale "") (user-scalable "")) :html-inline-images t :html-table-attributes (:border "2" :cellspacing "0" :cellpadding "6" :rules "groups" :frame "hsides") :html-table-row-open-tag "\n
" :html-format-drawer-function #f(compiled-function (name contents) #%s:
\n\n%s\n
\nDate: %d
\n%c
\n%v
")) :html-preamble-format (("en" "")) :html-prefer-user-labels nil :html-self-link-headlines nil :html-table-align-individual-fields t :html-table-caption-above t :html-table-data-tags ("%s
") (italic . "%s") (strike-through . "%s
")) :html-todo-kwd-class-prefix "" :html-toplevel-hlevel 2 :html-use-infojs when-configured :html-validation-link "Validate" :html-viewport ((width "device-width") (initial-scale "1") (minimum-scale "") (maximum-scale "") (user-scalable "")) :html-inline-images t :html-table-attributes (:border "2" :cellspacing "0" :cellpadding "6" :rules "groups" :frame "hsides") :html-table-row-open-tag "\n
" :html-format-drawer-function #f(compiled-function (name contents) #%s:
\n\n%s\n
\nDate: %d
\n%c
\n%v
")) :html-preamble-format (("en" "")) :html-prefer-user-labels nil :html-self-link-headlines nil :html-table-align-individual-fields t :html-table-caption-above t :html-table-data-tags ("%s
") (italic . "%s") (strike-through . "%s
")) :html-todo-kwd-class-prefix "" :html-toplevel-hlevel 2 :html-use-infojs when-configured :html-validation-link "Validate" :html-viewport ((width "device-width") (initial-scale "1") (minimum-scale "") (maximum-scale "") (user-scalable "")) :html-inline-images t :html-table-attributes (:border "2" :cellspacing "0" :cellpadding "6" :rules "groups" :frame "hsides") :html-table-row-open-tag "\n
" :html-format-drawer-function #f(compiled-function (name contents) #%s:
\n\n%s\n
\nDate: %d
\n%c
\n%v
")) :html-preamble-format (("en" "")) :html-prefer-user-labels nil :html-self-link-headlines nil :html-table-align-individual-fields t :html-table-caption-above t :html-table-data-tags ("%s
") (italic . "%s") (strike-through . "%s
")) :html-todo-kwd-class-prefix "" :html-toplevel-hlevel 2 :html-use-infojs when-configured :html-validation-link "Validate" :html-viewport ((width "device-width") (initial-scale "1") (minimum-scale "") (maximum-scale "") (user-scalable "")) :html-inline-images t :html-table-attributes (:border "2" :cellspacing "0" :cellpadding "6" :rules "groups" :frame "hsides") :html-table-row-open-tag "