12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643 |
- \input texinfo
- @c -*-texinfo-*-
- @c %**start of header
- @setfilename guix-cookbook.info
- @documentencoding UTF-8
- @settitle GNU Guix Cookbook
- @c %**end of header
- @c Onion service for ci.guix.gnu.org.
- @set SUBSTITUTE-TOR-URL https://4zwzi66wwdaalbhgnix55ea3ab4pvvw66ll2ow53kjub6se4q2bclcyd.onion
- @copying
- Copyright @copyright{} 2019, 2022 Ricardo Wurmus@*
- Copyright @copyright{} 2019 Efraim Flashner@*
- Copyright @copyright{} 2019 Pierre Neidhardt@*
- Copyright @copyright{} 2020 Oleg Pykhalov@*
- Copyright @copyright{} 2020 Matthew Brooks@*
- Copyright @copyright{} 2020 Marcin Karpezo@*
- Copyright @copyright{} 2020 Brice Waegeneire@*
- Copyright @copyright{} 2020 André Batista@*
- Copyright @copyright{} 2020 Christine Lemmer-Webber@*
- Copyright @copyright{} 2021 Joshua Branson@*
- Copyright @copyright{} 2022, 2023 Maxim Cournoyer@*
- Copyright @copyright{} 2023 Ludovic Courtès
- Copyright @copyright{} 2023 Thomas Ieong
- Permission is granted to copy, distribute and/or modify this document
- under the terms of the GNU Free Documentation License, Version 1.3 or
- any later version published by the Free Software Foundation; with no
- Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
- copy of the license is included in the section entitled ``GNU Free
- Documentation License''.
- @end copying
- @dircategory System administration
- @direntry
- * Guix cookbook: (guix-cookbook). Tutorials and examples for GNU Guix.
- @end direntry
- @titlepage
- @title GNU Guix Cookbook
- @subtitle Tutorials and examples for using the GNU Guix Functional Package Manager
- @author The GNU Guix Developers
- @page
- @vskip 0pt plus 1filll
- @insertcopying
- @end titlepage
- @contents
- @c *********************************************************************
- @node Top
- @top GNU Guix Cookbook
- This document presents tutorials and detailed examples for GNU@tie{}Guix, a
- functional package management tool written for the GNU system. Please
- @pxref{Top,,, guix, GNU Guix reference manual} for details about the system,
- its API, and related concepts.
- @c TRANSLATORS: You can replace the following paragraph with information on
- @c how to join your own translation team and how to report issues with the
- @c translation.
- This manual is also available in French (@pxref{Top,,, guix-cookbook.fr,
- Livre de recettes de GNU Guix}), German (@pxref{Top,,,
- guix-cookbook.de, GNU-Guix-Kochbuch}) and Slovak (@pxref{Top,,,
- guix-cookbook.sk, Receptár GNU Guix}). If you would like to translate
- this document in your native language, consider joining
- @uref{https://translate.fedoraproject.org/projects/guix/documentation-cookbook,
- Weblate} (@pxref{Translating Guix,,, guix, GNU Guix reference
- manual}).
- @menu
- * Scheme tutorials:: Meet your new favorite language!
- * Packaging:: Packaging tutorials
- * System Configuration:: Customizing the GNU System
- * Containers:: Isolated environments and nested systems
- * Advanced package management:: Power to the users!
- * Environment management:: Control environment
- * Installing Guix on a Cluster:: High-performance computing.
- * Acknowledgments:: Thanks!
- * GNU Free Documentation License:: The license of this document.
- * Concept Index:: Concepts.
- @detailmenu
- --- The Detailed Node Listing ---
- Scheme tutorials
- * A Scheme Crash Course::
- Packaging
- * Packaging Tutorial:: A tutorial on how to add packages to Guix.
- Packaging Tutorial
- * A ``Hello World'' package::
- * Setup::
- * Extended example::
- * Other build systems::
- * Programmable and automated package definition::
- * Getting help::
- * Conclusion::
- * References::
- Setup
- * Local file::
- * Channels::
- * Direct checkout hacking::
- Programmable and automated package definition
- * Recursive importers::
- * Automatic update::
- * Inheritance::
- System Configuration
- * Auto-Login to a Specific TTY:: Automatically Login a User to a Specific TTY
- * Customizing the Kernel:: Creating and using a custom Linux kernel on Guix System.
- * Guix System Image API:: Customizing images to target specific platforms.
- * Using security keys:: How to use security keys with Guix System.
- * Dynamic DNS mcron job:: Job to update the IP address behind a DuckDNS host name.
- * Connecting to Wireguard VPN:: Connecting to a Wireguard VPN.
- * Customizing a Window Manager:: Handle customization of a Window manager on Guix System.
- * Running Guix on a Linode Server:: Running Guix on a Linode Server.
- * Running Guix on a Kimsufi Server:: Running Guix on a Kimsufi Server.
- * Setting up a bind mount:: Setting up a bind mount in the file-systems definition.
- * Getting substitutes from Tor:: Configuring Guix daemon to get substitutes through Tor.
- * Setting up NGINX with Lua:: Configuring NGINX web-server to load Lua modules.
- * Music Server with Bluetooth Audio:: Headless music player with Bluetooth output.
- Customizing a Window Manager
- * StumpWM::
- * Session lock::
- Session lock
- * Xorg::
- Containers
- * Guix Containers:: Perfectly isolated environments
- * Guix System Containers:: A system inside your system
- Guix System Containers
- * A Database Container::
- * Container Networking::
- Advanced package management
- * Guix Profiles in Practice:: Strategies for multiple profiles and manifests.
- Guix Profiles in Practice
- * Basic setup with manifests::
- * Required packages::
- * Default profile::
- * The benefits of manifests::
- * Reproducible profiles::
- Environment management
- * Guix environment via direnv:: Setup Guix environment with direnv
- Installing Guix on a Cluster
- * Setting Up a Head Node:: The node that runs the daemon.
- * Setting Up Compute Nodes:: Client nodes.
- * Cluster Network Access:: Dealing with network access restrictions.
- * Cluster Disk Usage:: Disk usage considerations.
- * Cluster Security Considerations:: Keeping the cluster secure.
- @end detailmenu
- @end menu
- @c *********************************************************************
- @node Scheme tutorials
- @chapter Scheme tutorials
- GNU@tie{}Guix is written in the general purpose programming language Scheme,
- and many of its features can be accessed and manipulated programmatically.
- You can use Scheme to generate package definitions, to modify them, to build
- them, to deploy whole operating systems, etc.
- Knowing the basics of how to program in Scheme will unlock many of the
- advanced features Guix provides --- and you don't even need to be an
- experienced programmer to use them!
- Let's get started!
- @menu
- * A Scheme Crash Course::
- @end menu
- @node A Scheme Crash Course
- @section A Scheme Crash Course
- @cindex Scheme, crash course
- Guix uses the Guile implementation of Scheme. To start playing with the
- language, install it with @code{guix install guile} and start a
- @dfn{REPL}---short for @uref{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop,
- @dfn{read-eval-print loop}}---by running @code{guile} from the command line.
- Alternatively you can also run @code{guix shell guile -- guile}
- if you'd rather not have Guile installed in your user profile.
- In the following examples, lines show what you would type at the REPL;
- lines starting with ``@result{}'' show evaluation results, while lines
- starting with ``@print{}'' show things that get printed. @xref{Using Guile
- Interactively,,, guile, GNU Guile Reference Manual}, for more details on the
- REPL.
- @itemize
- @item
- Scheme syntax boils down to a tree of expressions (or @emph{s-expression} in
- Lisp lingo). An expression can be a literal such as numbers and strings, or a
- compound which is a parenthesized list of compounds and literals. @code{#true}
- and @code{#false} (abbreviated @code{#t} and @code{#f}) stand for the
- Booleans ``true'' and ``false'', respectively.
- Examples of valid expressions:
- @lisp
- "Hello World!"
- @result{} "Hello World!"
- 17
- @result{} 17
- (display (string-append "Hello " "Guix" "\n"))
- @print{} Hello Guix!
- @result{} #<unspecified>
- @end lisp
- @item
- This last example is a function call nested in another function call. When a
- parenthesized expression is evaluated, the first term is the function and the
- rest are the arguments passed to the function. Every function returns the
- last evaluated expression as its return value.
- @item
- Anonymous functions---@dfn{procedures} in Scheme parlance---are declared
- with the @code{lambda} term:
- @lisp
- (lambda (x) (* x x))
- @result{} #<procedure 120e348 at <unknown port>:24:0 (x)>
- @end lisp
- The above procedure returns the square of its argument. Since everything is
- an expression, the @code{lambda} expression returns an anonymous procedure,
- which can in turn be applied to an argument:
- @lisp
- ((lambda (x) (* x x)) 3)
- @result{} 9
- @end lisp
- Procedures are regular values just like numbers, strings, Booleans, and
- so on.
- @item
- Anything can be assigned a global name with @code{define}:
- @lisp
- (define a 3)
- (define square (lambda (x) (* x x)))
- (square a)
- @result{} 9
- @end lisp
- @item
- Procedures can be defined more concisely with the following syntax:
- @lisp
- (define (square x) (* x x))
- @end lisp
- @item
- A list structure can be created with the @code{list} procedure:
- @lisp
- (list 2 a 5 7)
- @result{} (2 3 5 7)
- @end lisp
- @item
- Standard procedures are provided by the @code{(srfi srfi-1)} module to
- create and process lists (@pxref{SRFI-1, list processing,, guile, GNU
- Guile Reference Manual}). Here are some of the most useful ones in
- action:
- @lisp
- (use-modules (srfi srfi-1)) ;import list processing procedures
- (append (list 1 2) (list 3 4))
- @result{} (1 2 3 4)
- (map (lambda (x) (* x x)) (list 1 2 3 4))
- @result{} (1 4 9 16)
- (delete 3 (list 1 2 3 4)) @result{} (1 2 4)
- (filter odd? (list 1 2 3 4)) @result{} (1 3)
- (remove even? (list 1 2 3 4)) @result{} (1 3)
- (find number? (list "a" 42 "b")) @result{} 42
- @end lisp
- Notice how the first argument to @code{map}, @code{filter},
- @code{remove}, and @code{find} is a procedure!
- @item
- @cindex S-expression
- The @dfn{quote} disables evaluation of a parenthesized expression, also
- called an S-expression or ``s-exp'': the first term is not called over
- the other terms (@pxref{Expression Syntax, quote,, guile, GNU Guile
- Reference Manual}). Thus it effectively returns a list of terms.
- @lisp
- '(display (string-append "Hello " "Guix" "\n"))
- @result{} (display (string-append "Hello " "Guix" "\n"))
- '(2 a 5 7)
- @result{} (2 a 5 7)
- @end lisp
- @item
- The @code{quasiquote} (@code{`}, a backquote) disables evaluation of a
- parenthesized expression until @code{unquote} (@code{,}, a comma)
- re-enables it. Thus it provides us with fine-grained control over what
- is evaluated and what is not.
- @lisp
- `(2 a 5 7 (2 ,a 5 ,(+ a 4)))
- @result{} (2 a 5 7 (2 3 5 7))
- @end lisp
- Note that the above result is a list of mixed elements: numbers, symbols (here
- @code{a}) and the last element is a list itself.
- @item
- @cindex G-expressions, syntax
- @cindex gexps, syntax
- @findex #~
- @findex #$
- @findex gexp
- @findex ungexp
- Guix defines a variant of S-expressions on steroids called
- @dfn{G-expressions} or ``gexps'', which come with a variant of
- @code{quasiquote} and @code{unquote}: @code{#~} (or @code{gexp}) and
- @code{#$} (or @code{ungexp}). They let you @emph{stage code for later
- execution}.
- For example, you'll encounter gexps in some package definitions where
- they provide code to be executed during the package build process. They
- look like this:
- @lisp
- (use-modules (guix gexp) ;so we can write gexps
- (gnu packages base)) ;for 'coreutils'
- ;; Below is a G-expression representing staged code.
- #~(begin
- ;; Invoke 'ls' from the package defined by the 'coreutils'
- ;; variable.
- (system* #$(file-append coreutils "/bin/ls") "-l")
- ;; Create this package's output directory.
- (mkdir #$output))
- @end lisp
- @xref{G-Expressions,,, guix, GNU Guix Reference Manual}, for more on
- gexps.
- @item
- Multiple variables can be named locally with @code{let} (@pxref{Local
- Bindings,,, guile, GNU Guile Reference Manual}):
- @lisp
- (define x 10)
- (let ((x 2)
- (y 3))
- (list x y))
- @result{} (2 3)
- x
- @result{} 10
- y
- @error{} In procedure module-lookup: Unbound variable: y
- @end lisp
- Use @code{let*} to allow later variable declarations to refer to earlier
- definitions.
- @lisp
- (let* ((x 2)
- (y (* x 3)))
- (list x y))
- @result{} (2 6)
- @end lisp
- @item
- @dfn{Keywords} are typically used to identify the named parameters of a
- procedure. They are prefixed by @code{#:} (hash, colon) followed by
- alphanumeric characters: @code{#:like-this}.
- @xref{Keywords,,, guile, GNU Guile Reference Manual}.
- @item
- The percentage @code{%} is typically used for read-only global variables in
- the build stage. Note that it is merely a convention, like @code{_} in C.
- Scheme treats @code{%} exactly the same as any other letter.
- @item
- Modules are created with @code{define-module} (@pxref{Creating Guile
- Modules,,, guile, GNU Guile Reference Manual}). For instance
- @lisp
- (define-module (guix build-system ruby)
- #:use-module (guix store)
- #:export (ruby-build
- ruby-build-system))
- @end lisp
- defines the module @code{guix build-system ruby} which must be located in
- @file{guix/build-system/ruby.scm} somewhere in the Guile load path. It
- depends on the @code{(guix store)} module and it exports two variables,
- @code{ruby-build} and @code{ruby-build-system}.
- @xref{Package Modules,,, guix, GNU Guix Reference Manual}, for info on
- modules that define packages.
- @end itemize
- @quotation Going further
- Scheme is a language that has been widely used to teach programming and
- you'll find plenty of material using it as a vehicle. Here's a
- selection of documents to learn more about Scheme:
- @itemize
- @item
- @uref{https://spritely.institute/static/papers/scheme-primer.html, @i{A
- Scheme Primer}}, by Christine Lemmer-Webber and the Spritely Institute.
- @item
- @uref{http://www.troubleshooters.com/codecorn/scheme_guile/hello.htm,
- @i{Scheme at a Glance}}, by Steve Litt.
- @item
- @c There used to be a copy at mitpress.mit.edu but it vanished.
- @uref{https://sarabander.github.io/sicp/,
- @i{Structure and Interpretation of Computer Programs}}, by Harold
- Abelson and Gerald Jay Sussman, with Julie Sussman. Colloquially known
- as ``SICP'', this book is a reference.
- You can also install it and read it from your computer:
- @example
- guix install sicp info-reader
- info sicp
- @end example
- @end itemize
- You'll find more books, tutorials and other resources at
- @url{https://schemers.org/}.
- @end quotation
- @c *********************************************************************
- @node Packaging
- @chapter Packaging
- @cindex packaging
- This chapter is dedicated to teaching you how to add packages to the
- collection of packages that come with GNU Guix. This involves writing package
- definitions in Guile Scheme, organizing them in package modules, and building
- them.
- @menu
- * Packaging Tutorial:: A tutorial on how to add packages to Guix.
- @end menu
- @node Packaging Tutorial
- @section Packaging Tutorial
- GNU Guix stands out as the @emph{hackable} package manager, mostly because it
- uses @uref{https://www.gnu.org/software/guile/, GNU Guile}, a powerful
- high-level programming language, one of the
- @uref{https://en.wikipedia.org/wiki/Scheme_%28programming_language%29, Scheme}
- dialects from the
- @uref{https://en.wikipedia.org/wiki/Lisp_%28programming_language%29, Lisp family}.
- Package definitions are also written in Scheme, which empowers Guix in some
- very unique ways, unlike most other package managers that use shell scripts or
- simple languages.
- @itemize
- @item
- Use functions, structures, macros and all of Scheme expressiveness for your
- package definitions.
- @item
- Inheritance makes it easy to customize a package by inheriting from it and
- modifying only what is needed.
- @item
- Batch processing: the whole package collection can be parsed, filtered and
- processed. Building a headless server with all graphical interfaces stripped
- out? It's possible. Want to rebuild everything from source using specific
- compiler optimization flags? Pass the @code{#:make-flags "..."} argument to
- the list of packages. It wouldn't be a stretch to think
- @uref{https://wiki.gentoo.org/wiki/USE_flag, Gentoo USE flags} here, but this
- goes even further: the changes don't have to be thought out beforehand by the
- packager, they can be @emph{programmed} by the user!
- @end itemize
- The following tutorial covers all the basics around package creation with Guix.
- It does not assume much knowledge of the Guix system nor of the Lisp language.
- The reader is only expected to be familiar with the command line and to have some
- basic programming knowledge.
- @menu
- * A ``Hello World'' package::
- * Setup::
- * Extended example::
- * Other build systems::
- * Programmable and automated package definition::
- * Getting help::
- * Conclusion::
- * References::
- @end menu
- @node A ``Hello World'' package
- @subsection A ``Hello World'' package
- The ``Defining Packages'' section of the manual introduces the basics of Guix
- packaging (@pxref{Defining Packages,,, guix, GNU Guix Reference Manual}). In
- the following section, we will partly go over those basics again.
- GNU@tie{}Hello is a dummy project that serves as an idiomatic example for
- packaging. It uses the GNU build system (@code{./configure && make && make
- install}). Guix already provides a package definition which is a perfect
- example to start with. You can look up its declaration with @code{guix edit
- hello} from the command line. Let's see how it looks:
- @lisp
- (define-public hello
- (package
- (name "hello")
- (version "2.10")
- (source (origin
- (method url-fetch)
- (uri (string-append "mirror://gnu/hello/hello-" version
- ".tar.gz"))
- (sha256
- (base32
- "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
- (build-system gnu-build-system)
- (synopsis "Hello, GNU world: An example GNU package")
- (description
- "GNU Hello prints the message \"Hello, world!\" and then exits. It
- serves as an example of standard GNU coding practices. As such, it supports
- command-line arguments, multiple languages, and so on.")
- (home-page "https://www.gnu.org/software/hello/")
- (license gpl3+)))
- @end lisp
- As you can see, most of it is rather straightforward. But let's review the
- fields together:
- @table @samp
- @item name
- The project name. Using Scheme conventions, we prefer to keep it
- lower case, without underscore and using dash-separated words.
- @item source
- This field contains a description of the source code origin. The
- @code{origin} record contains these fields:
- @enumerate
- @item The method, here @code{url-fetch} to download via HTTP/FTP, but other methods
- exist, such as @code{git-fetch} for Git repositories.
- @item The URI, which is typically some @code{https://} location for @code{url-fetch}. Here
- the special `mirror://gnu` refers to a set of well known locations, all of
- which can be used by Guix to fetch the source, should some of them fail.
- @item The @code{sha256} checksum of the requested file. This is essential to ensure
- the source is not corrupted. Note that Guix works with base32 strings,
- hence the call to the @code{base32} function.
- @end enumerate
- @item build-system
- This is where the power of abstraction provided by the Scheme language really
- shines: in this case, the @code{gnu-build-system} abstracts away the famous
- @code{./configure && make && make install} shell invocations. Other build
- systems include the @code{trivial-build-system} which does not do anything and
- requires from the packager to program all the build steps, the
- @code{python-build-system}, the @code{emacs-build-system}, and many more
- (@pxref{Build Systems,,, guix, GNU Guix Reference Manual}).
- @item synopsis
- It should be a concise summary of what the package does. For many packages a
- tagline from the project's home page can be used as the synopsis.
- @item description
- Same as for the synopsis, it's fine to re-use the project description from the
- homepage. Note that Guix uses Texinfo syntax.
- @item home-page
- Use HTTPS if available.
- @item license
- See @code{guix/licenses.scm} in the project source for a full list of
- available licenses.
- @end table
- Time to build our first package! Nothing fancy here for now: we will stick to a
- dummy @code{my-hello}, a copy of the above declaration.
- As with the ritualistic ``Hello World'' taught with most programming languages,
- this will possibly be the most ``manual'' approach. We will work out an ideal
- setup later; for now we will go the simplest route.
- Save the following to a file @file{my-hello.scm}.
- @lisp
- (use-modules (guix packages)
- (guix download)
- (guix build-system gnu)
- (guix licenses))
- (package
- (name "my-hello")
- (version "2.10")
- (source (origin
- (method url-fetch)
- (uri (string-append "mirror://gnu/hello/hello-" version
- ".tar.gz"))
- (sha256
- (base32
- "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
- (build-system gnu-build-system)
- (synopsis "Hello, Guix world: An example custom Guix package")
- (description
- "GNU Hello prints the message \"Hello, world!\" and then exits. It
- serves as an example of standard GNU coding practices. As such, it supports
- command-line arguments, multiple languages, and so on.")
- (home-page "https://www.gnu.org/software/hello/")
- (license gpl3+))
- @end lisp
- We will explain the extra code in a moment.
- Feel free to play with the different values of the various fields. If you
- change the source, you'll need to update the checksum. Indeed, Guix refuses to
- build anything if the given checksum does not match the computed checksum of the
- source code. To obtain the correct checksum of the package declaration, we
- need to download the source, compute the sha256 checksum and convert it to
- base32.
- Thankfully, Guix can automate this task for us; all we need is to provide the
- URI:
- @c TRANSLATORS: This is example shell output.
- @example sh
- $ guix download mirror://gnu/hello/hello-2.10.tar.gz
- Starting download of /tmp/guix-file.JLYgL7
- From https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz...
- following redirection to `https://mirror.ibcp.fr/pub/gnu/hello/hello-2.10.tar.gz'...
- …10.tar.gz 709KiB 2.5MiB/s 00:00 [##################] 100.0%
- /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz
- 0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i
- @end example
- In this specific case the output tells us which mirror was chosen.
- If the result of the above command is not the same as in the above snippet,
- update your @code{my-hello} declaration accordingly.
- Note that GNU package tarballs come with an OpenPGP signature, so you
- should definitely check the signature of this tarball with `gpg` to
- authenticate it before going further:
- @c TRANSLATORS: This is example shell output.
- @example sh
- $ guix download mirror://gnu/hello/hello-2.10.tar.gz.sig
- Starting download of /tmp/guix-file.03tFfb
- From https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz.sig...
- following redirection to `https://ftp.igh.cnrs.fr/pub/gnu/hello/hello-2.10.tar.gz.sig'...
- ….tar.gz.sig 819B 1.2MiB/s 00:00 [##################] 100.0%
- /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig
- 0q0v86n3y38z17rl146gdakw9xc4mcscpk8dscs412j22glrv9jf
- $ gpg --verify /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz
- gpg: Signature made Sun 16 Nov 2014 01:08:37 PM CET
- gpg: using RSA key A9553245FDE9B739
- gpg: Good signature from "Sami Kerola <kerolasa@@iki.fi>" [unknown]
- gpg: aka "Sami Kerola (http://www.iki.fi/kerolasa/) <kerolasa@@iki.fi>" [unknown]
- gpg: WARNING: This key is not certified with a trusted signature!
- gpg: There is no indication that the signature belongs to the owner.
- Primary key fingerprint: 8ED3 96E3 7E38 D471 A005 30D3 A955 3245 FDE9 B739
- @end example
- You can then happily run
- @c TRANSLATORS: Do not translate this command
- @example sh
- $ guix package --install-from-file=my-hello.scm
- @end example
- You should now have @code{my-hello} in your profile!
- @c TRANSLATORS: Do not translate this command
- @example sh
- $ guix package --list-installed=my-hello
- my-hello 2.10 out
- /gnu/store/f1db2mfm8syb8qvc357c53slbvf1g9m9-my-hello-2.10
- @end example
- We've gone as far as we could without any knowledge of Scheme. Before moving
- on to more complex packages, now is the right time to brush up on your Scheme
- knowledge. @pxref{A Scheme Crash Course} to get up to speed.
- @node Setup
- @subsection Setup
- In the rest of this chapter we will rely on some basic Scheme
- programming knowledge. Now let's detail the different possible setups
- for working on Guix packages.
- There are several ways to set up a Guix packaging environment.
- We recommend you work directly on the Guix source checkout since it makes it
- easier for everyone to contribute to the project.
- But first, let's look at other possibilities.
- @menu
- * Local file::
- * Channels::
- * Direct checkout hacking::
- @end menu
- @node Local file
- @subsubsection Local file
- This is what we previously did with @samp{my-hello}. With the Scheme basics we've
- covered, we are now able to explain the leading chunks. As stated in @code{guix
- package --help}:
- @example
- -f, --install-from-file=FILE
- install the package that the code within FILE
- evaluates to
- @end example
- Thus the last expression @emph{must} return a package, which is the case in our
- earlier example.
- The @code{use-modules} expression tells which of the modules we need in the file.
- Modules are a collection of values and procedures. They are commonly called
- ``libraries'' or ``packages'' in other programming languages.
- @node Channels
- @subsubsection Channels
- @cindex channel
- Guix and its package collection can be extended through @dfn{channels}.
- A channel is a Git repository, public or not, containing @file{.scm}
- files that provide packages (@pxref{Defining Packages,,, guix, GNU Guix
- Reference Manual}) or services (@pxref{Defining Services,,, guix, GNU
- Guix Reference Manual}).
- How would you go about creating a channel? First, create a directory
- that will contain your @file{.scm} files, say @file{~/my-channel}:
- @example
- mkdir ~/my-channel
- @end example
- Suppose you want to add the @samp{my-hello} package we saw previously;
- it first needs some adjustments:
- @lisp
- (define-module (my-hello)
- #:use-module (guix licenses)
- #:use-module (guix packages)
- #:use-module (guix build-system gnu)
- #:use-module (guix download))
- (define-public my-hello
- (package
- (name "my-hello")
- (version "2.10")
- (source (origin
- (method url-fetch)
- (uri (string-append "mirror://gnu/hello/hello-" version
- ".tar.gz"))
- (sha256
- (base32
- "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
- (build-system gnu-build-system)
- (synopsis "Hello, Guix world: An example custom Guix package")
- (description
- "GNU Hello prints the message \"Hello, world!\" and then exits. It
- serves as an example of standard GNU coding practices. As such, it supports
- command-line arguments, multiple languages, and so on.")
- (home-page "https://www.gnu.org/software/hello/")
- (license gpl3+)))
- @end lisp
- Note that we have assigned the package value to an exported variable name with
- @code{define-public}. This is effectively assigning the package to the @code{my-hello}
- variable so that it can be referenced, among other as dependency of other
- packages.
- If you use @code{guix package --install-from-file=my-hello.scm} on the above file, it
- will fail because the last expression, @code{define-public}, does not return a
- package. If you want to use @code{define-public} in this use-case nonetheless, make
- sure the file ends with an evaluation of @code{my-hello}:
- @lisp
- ;; ...
- (define-public my-hello
- ;; ...
- )
- my-hello
- @end lisp
- This last example is not very typical.
- Now how do you make that package visible to @command{guix} commands so
- you can test your packages? You need to add the directory to the search
- path using the @option{-L} command-line option, as in these examples:
- @example
- guix show -L ~/my-channel my-hello
- guix build -L ~/my-channel my-hello
- @end example
- The final step is to turn @file{~/my-channel} into an actual channel,
- making your package collection seamlessly available @i{via} any
- @command{guix} command. To do that, you first need to make it a Git
- repository:
- @example
- cd ~/my-channel
- git init
- git add my-hello.scm
- git commit -m "First commit of my channel."
- @end example
- And that's it, you have a channel! From there on, you can add this
- channel to your channel configuration in
- @file{~/.config/guix/channels.scm} (@pxref{Specifying Additional
- Channels,,, guix, GNU Guix Reference Manual}); assuming you keep your
- channel local for now, the @file{channels.scm} would look something like
- this:
- @lisp
- (append (list (channel
- (name 'my-channel)
- (url (string-append "file://" (getenv "HOME")
- "/my-channel"))))
- %default-channels)
- @end lisp
- Next time you run @command{guix pull}, your channel will be picked up
- and the packages it defines will be readily available to all the
- @command{guix} commands, even if you do not pass @option{-L}. The
- @command{guix describe} command will show that Guix is, indeed, using
- both the @code{my-channel} and the @code{guix} channels.
- @xref{Creating a Channel,,, guix, GNU Guix Reference Manual}, for
- details.
- @node Direct checkout hacking
- @subsubsection Direct checkout hacking
- Working directly on the Guix project is recommended: it reduces the friction
- when the time comes to submit your changes upstream to let the community benefit
- from your hard work!
- Unlike most software distributions, the Guix repository holds in one place both
- the tooling (including the package manager) and the package definitions. This
- choice was made so that it would give developers the flexibility to modify the
- API without breakage by updating all packages at the same time. This reduces
- development inertia.
- Check out the official @uref{https://git-scm.com/, Git} repository:
- @example
- $ git clone https://git.savannah.gnu.org/git/guix.git
- @end example
- In the rest of this article, we use @samp{$GUIX_CHECKOUT} to refer to the location of
- the checkout.
- Follow the instructions in the manual (@pxref{Contributing,,, guix, GNU Guix
- Reference Manual}) to set up the repository environment.
- Once ready, you should be able to use the package definitions from the
- repository environment.
- Feel free to edit package definitions found in @samp{$GUIX_CHECKOUT/gnu/packages}.
- The @samp{$GUIX_CHECKOUT/pre-inst-env} script lets you use @samp{guix} over the package
- collection of the repository (@pxref{Running Guix Before It Is
- Installed,,, guix, GNU Guix Reference Manual}).
- @itemize
- @item
- Search packages, such as Ruby:
- @example
- $ cd $GUIX_CHECKOUT
- $ ./pre-inst-env guix package --list-available=ruby
- ruby 1.8.7-p374 out gnu/packages/ruby.scm:119:2
- ruby 2.1.6 out gnu/packages/ruby.scm:91:2
- ruby 2.2.2 out gnu/packages/ruby.scm:39:2
- @end example
- @item
- Build a package, here Ruby version 2.1:
- @example
- $ ./pre-inst-env guix build --keep-failed ruby@@2.1
- /gnu/store/c13v73jxmj2nir2xjqaz5259zywsa9zi-ruby-2.1.6
- @end example
- @item
- Install it to your user profile:
- @example
- $ ./pre-inst-env guix package --install ruby@@2.1
- @end example
- @item
- Check for common mistakes:
- @example
- $ ./pre-inst-env guix lint ruby@@2.1
- @end example
- @end itemize
- Guix strives at maintaining a high packaging standard; when contributing to the
- Guix project, remember to
- @itemize
- @item
- follow the coding style (@pxref{Coding Style,,, guix, GNU Guix Reference Manual}),
- @item
- and review the check list from the manual (@pxref{Submitting Patches,,, guix, GNU Guix Reference Manual}).
- @end itemize
- Once you are happy with the result, you are welcome to send your contribution to
- make it part of Guix. This process is also detailed in the manual. (@pxref{Contributing,,, guix, GNU Guix Reference Manual})
- It's a community effort so the more join in, the better Guix becomes!
- @node Extended example
- @subsection Extended example
- The above ``Hello World'' example is as simple as it goes. Packages can be more
- complex than that and Guix can handle more advanced scenarios. Let's look at
- another, more sophisticated package (slightly modified from the source):
- @lisp
- (define-module (gnu packages version-control)
- #:use-module ((guix licenses) #:prefix license:)
- #:use-module (guix utils)
- #:use-module (guix packages)
- #:use-module (guix git-download)
- #:use-module (guix build-system cmake)
- #:use-module (gnu packages compression)
- #:use-module (gnu packages pkg-config)
- #:use-module (gnu packages python)
- #:use-module (gnu packages ssh)
- #:use-module (gnu packages tls)
- #:use-module (gnu packages web))
- (define-public my-libgit2
- (let ((commit "e98d0a37c93574d2c6107bf7f31140b548c6a7bf")
- (revision "1"))
- (package
- (name "my-libgit2")
- (version (git-version "0.26.6" revision commit))
- (source (origin
- (method git-fetch)
- (uri (git-reference
- (url "https://github.com/libgit2/libgit2/")
- (commit commit)))
- (file-name (git-file-name name version))
- (sha256
- (base32
- "17pjvprmdrx4h6bb1hhc98w9qi6ki7yl57f090n9kbhswxqfs7s3"))
- (patches (search-patches "libgit2-mtime-0.patch"))
- (modules '((guix build utils)))
- ;; Remove bundled software.
- (snippet '(delete-file-recursively "deps"))))
- (build-system cmake-build-system)
- (outputs '("out" "debug"))
- (arguments
- `(#:tests? #true ; Run the test suite (this is the default)
- #:configure-flags '("-DUSE_SHA1DC=ON") ; SHA-1 collision detection
- #:phases
- (modify-phases %standard-phases
- (add-after 'unpack 'fix-hardcoded-paths
- (lambda _
- (substitute* "tests/repo/init.c"
- (("#!/bin/sh") (string-append "#!" (which "sh"))))
- (substitute* "tests/clar/fs.h"
- (("/bin/cp") (which "cp"))
- (("/bin/rm") (which "rm")))))
- ;; Run checks more verbosely.
- (replace 'check
- (lambda* (#:key tests? #:allow-other-keys)
- (when tests?
- (invoke "./libgit2_clar" "-v" "-Q"))))
- (add-after 'unpack 'make-files-writable-for-tests
- (lambda _ (for-each make-file-writable (find-files ".")))))))
- (inputs
- (list libssh2 http-parser python-wrapper))
- (native-inputs
- (list pkg-config))
- (propagated-inputs
- ;; These two libraries are in 'Requires.private' in libgit2.pc.
- (list openssl zlib))
- (home-page "https://libgit2.github.com/")
- (synopsis "Library providing Git core methods")
- (description
- "Libgit2 is a portable, pure C implementation of the Git core methods
- provided as a re-entrant linkable library with a solid API, allowing you to
- write native speed custom Git applications in any language with bindings.")
- ;; GPLv2 with linking exception
- (license license:gpl2))))
- @end lisp
- (In those cases were you only want to tweak a few fields from a package
- definition, you should rely on inheritance instead of copy-pasting everything.
- See below.)
- Let's discuss those fields in depth.
- @subsubsection @code{git-fetch} method
- Unlike the @code{url-fetch} method, @code{git-fetch} expects a @code{git-reference} which takes
- a Git repository and a commit. The commit can be any Git reference such as
- tags, so if the @code{version} is tagged, then it can be used directly. Sometimes
- the tag is prefixed with a @code{v}, in which case you'd use @code{(commit (string-append
- "v" version))}.
- To ensure that the source code from the Git repository is stored in a
- directory with a descriptive name, we use @code{(file-name (git-file-name name
- version))}.
- The @code{git-version} procedure can be used to derive the
- version when packaging programs for a specific commit, following the
- Guix contributor guidelines (@pxref{Version Numbers,,, guix, GNU Guix
- Reference Manual}).
- How does one obtain the @code{sha256} hash that's in there, you ask? By
- invoking @command{guix hash} on a checkout of the desired commit, along
- these lines:
- @example
- git clone https://github.com/libgit2/libgit2/
- cd libgit2
- git checkout v0.26.6
- guix hash -rx .
- @end example
- @command{guix hash -rx} computes a SHA256 hash over the whole directory,
- excluding the @file{.git} sub-directory (@pxref{Invoking guix hash,,,
- guix, GNU Guix Reference Manual}).
- In the future, @command{guix download} will hopefully be able to do
- these steps for you, just like it does for regular downloads.
- @subsubsection Snippets
- Snippets are quoted (i.e. non-evaluated) Scheme code that are a means of patching
- the source. They are a Guix-y alternative to the traditional @file{.patch} files.
- Because of the quote, the code in only evaluated when passed to the Guix daemon
- for building. There can be as many snippets as needed.
- Snippets might need additional Guile modules which can be imported from the
- @code{modules} field.
- @subsubsection Inputs
- There are 3 different input types. In short:
- @table @asis
- @item native-inputs
- Required for building but not runtime -- installing a package
- through a substitute won't install these inputs.
- @item inputs
- Installed in the store but not in the profile, as well as being
- present at build time.
- @item propagated-inputs
- Installed in the store and in the profile, as well as
- being present at build time.
- @end table
- @xref{package Reference,,, guix, GNU Guix Reference Manual} for more details.
- The distinction between the various inputs is important: if a dependency can be
- handled as an @emph{input} instead of a @emph{propagated input}, it should be done so, or
- else it ``pollutes'' the user profile for no good reason.
- For instance, a user installing a graphical program that depends on a
- command line tool might only be interested in the graphical part, so there is no
- need to force the command line tool into the user profile. The dependency is a
- concern to the package, not to the user. @emph{Inputs} make it possible to handle
- dependencies without bugging the user by adding undesired executable files (or
- libraries) to their profile.
- Same goes for @emph{native-inputs}: once the program is installed, build-time
- dependencies can be safely garbage-collected.
- It also matters when a substitute is available, in which case only the @emph{inputs}
- and @emph{propagated inputs} will be fetched: the @emph{native inputs} are not required to
- install a package from a substitute.
- @quotation Note
- You may see here and there snippets where package inputs are written
- quite differently, like so:
- @lisp
- ;; The "old style" for inputs.
- (inputs
- `(("libssh2" ,libssh2)
- ("http-parser" ,http-parser)
- ("python" ,python-wrapper)))
- @end lisp
- This is the ``old style'', where each input in the list is explicitly
- given a label (a string). It is still supported but we recommend using
- the style above instead. @xref{package Reference,,, guix, GNU Guix
- Reference Manual}, for more info.
- @end quotation
- @subsubsection Outputs
- Just like how a package can have multiple inputs, it can also produce multiple
- outputs.
- Each output corresponds to a separate directory in the store.
- The user can choose which output to install; this is useful to save space or
- to avoid polluting the user profile with unwanted executables or libraries.
- Output separation is optional. When the @code{outputs} field is left out, the
- default and only output (the complete package) is referred to as @code{"out"}.
- Typical separate output names include @code{debug} and @code{doc}.
- It's advised to separate outputs only when you've shown it's worth it: if the
- output size is significant (compare with @code{guix size}) or in case the package is
- modular.
- @subsubsection Build system arguments
- The @code{arguments} is a keyword-value list used to configure the build process.
- The simplest argument @code{#:tests?} can be used to disable the test suite when
- building the package. This is mostly useful when the package does not feature
- any test suite. It's strongly recommended to keep the test suite on if there is
- one.
- Another common argument is @code{:make-flags}, which specifies a list of flags to
- append when running make, as you would from the command line. For instance, the
- following flags
- @lisp
- #:make-flags (list (string-append "prefix=" (assoc-ref %outputs "out"))
- "CC=gcc")
- @end lisp
- translate into
- @example
- $ make CC=gcc prefix=/gnu/store/...-<out>
- @end example
- This sets the C compiler to @code{gcc} and the @code{prefix} variable (the installation
- directory in Make parlance) to @code{(assoc-ref %outputs "out")}, which is a build-stage
- global variable pointing to the destination directory in the store (something like
- @file{/gnu/store/...-my-libgit2-20180408}).
- Similarly, it's possible to set the configure flags:
- @lisp
- #:configure-flags '("-DUSE_SHA1DC=ON")
- @end lisp
- The @code{%build-inputs} variable is also generated in scope. It's an association
- table that maps the input names to their store directories.
- The @code{phases} keyword lists the sequential steps of the build system. Typically
- phases include @code{unpack}, @code{configure}, @code{build}, @code{install} and @code{check}. To know
- more about those phases, you need to work out the appropriate build system
- definition in @samp{$GUIX_CHECKOUT/guix/build/gnu-build-system.scm}:
- @lisp
- (define %standard-phases
- ;; Standard build phases, as a list of symbol/procedure pairs.
- (let-syntax ((phases (syntax-rules ()
- ((_ p ...) `((p . ,p) ...)))))
- (phases set-SOURCE-DATE-EPOCH set-paths install-locale unpack
- bootstrap
- patch-usr-bin-file
- patch-source-shebangs configure patch-generated-file-shebangs
- build check install
- patch-shebangs strip
- validate-runpath
- validate-documentation-location
- delete-info-dir-file
- patch-dot-desktop-files
- install-license-files
- reset-gzip-timestamps
- compress-documentation)))
- @end lisp
- Or from the REPL:
- @lisp
- (add-to-load-path "/path/to/guix/checkout")
- ,use (guix build gnu-build-system)
- (map first %standard-phases)
- @result{} (set-SOURCE-DATE-EPOCH set-paths install-locale unpack bootstrap patch-usr-bin-file patch-source-shebangs configure patch-generated-file-shebangs build check install patch-shebangs strip validate-runpath validate-documentation-location delete-info-dir-file patch-dot-desktop-files install-license-files reset-gzip-timestamps compress-documentation)
- @end lisp
- If you want to know more about what happens during those phases, consult the
- associated procedures.
- For instance, as of this writing the definition of @code{unpack} for the GNU build
- system is:
- @lisp
- (define* (unpack #:key source #:allow-other-keys)
- "Unpack SOURCE in the working directory, and change directory within the
- source. When SOURCE is a directory, copy it in a sub-directory of the current
- working directory."
- (if (file-is-directory? source)
- (begin
- (mkdir "source")
- (chdir "source")
- ;; Preserve timestamps (set to the Epoch) on the copied tree so that
- ;; things work deterministically.
- (copy-recursively source "."
- #:keep-mtime? #true))
- (begin
- (if (string-suffix? ".zip" source)
- (invoke "unzip" source)
- (invoke "tar" "xvf" source))
- (chdir (first-subdirectory "."))))
- #true)
- @end lisp
- Note the @code{chdir} call: it changes the working directory to where the source was
- unpacked.
- Thus every phase following the @code{unpack} will use the source as a working
- directory, which is why we can directly work on the source files.
- That is to say, unless a later phase changes the working directory to something
- else.
- We modify the list of @code{%standard-phases} of the build system with the
- @code{modify-phases} macro as per the list of specified modifications, which may have
- the following forms:
- @itemize
- @item
- @code{(add-before @var{phase} @var{new-phase} @var{procedure})}: Run @var{procedure} named @var{new-phase} before @var{phase}.
- @item
- @code{(add-after @var{phase} @var{new-phase} @var{procedure})}: Same, but afterwards.
- @item
- @code{(replace @var{phase} @var{procedure})}.
- @item
- @code{(delete @var{phase})}.
- @end itemize
- The @var{procedure} supports the keyword arguments @code{inputs} and @code{outputs}. Each
- input (whether @emph{native}, @emph{propagated} or not) and output directory is referenced
- by their name in those variables. Thus @code{(assoc-ref outputs "out")} is the store
- directory of the main output of the package. A phase procedure may look like
- this:
- @lisp
- (lambda* (#:key inputs outputs #:allow-other-keys)
- (let ((bash-directory (assoc-ref inputs "bash"))
- (output-directory (assoc-ref outputs "out"))
- (doc-directory (assoc-ref outputs "doc")))
- ;; ...
- #true))
- @end lisp
- The procedure must return @code{#true} on success. It's brittle to rely on the return
- value of the last expression used to tweak the phase because there is no
- guarantee it would be a @code{#true}. Hence the trailing @code{#true} to ensure the right value
- is returned on success.
- @subsubsection Code staging
- The astute reader may have noticed the quasi-quote and comma syntax in the
- argument field. Indeed, the build code in the package declaration should not be
- evaluated on the client side, but only when passed to the Guix daemon. This
- mechanism of passing code around two running processes is called @uref{https://arxiv.org/abs/1709.00833, code staging}.
- @subsubsection Utility functions
- When customizing @code{phases}, we often need to write code that mimics the
- equivalent system invocations (@code{make}, @code{mkdir}, @code{cp}, etc.)@: commonly used during
- regular ``Unix-style'' installations.
- Some like @code{chmod} are native to Guile.
- @xref{,,, guile, Guile reference manual} for a complete list.
- Guix provides additional helper functions which prove especially handy in the
- context of package management.
- Some of those functions can be found in
- @samp{$GUIX_CHECKOUT/guix/guix/build/utils.scm}. Most of them mirror the behaviour
- of the traditional Unix system commands:
- @table @code
- @item which
- Like the @samp{which} system command.
- @item find-files
- Akin to the @samp{find} system command.
- @item mkdir-p
- Like @samp{mkdir -p}, which creates all parents as needed.
- @item install-file
- Similar to @samp{install} when installing a file to a (possibly
- non-existing) directory. Guile has @code{copy-file} which works
- like @samp{cp}.
- @item copy-recursively
- Like @samp{cp -r}.
- @item delete-file-recursively
- Like @samp{rm -rf}.
- @item invoke
- Run an executable. This should be used instead of @code{system*}.
- @item with-directory-excursion
- Run the body in a different working directory,
- then restore the previous working directory.
- @item substitute*
- A ``@command{sed}-like'' function.
- @end table
- @xref{Build Utilities,,, guix, GNU Guix Reference Manual}, for more
- information on these utilities.
- @subsubsection Module prefix
- The license in our last example needs a prefix: this is because of how the
- @code{license} module was imported in the package, as @code{#:use-module ((guix licenses)
- #:prefix license:)}. The Guile module import mechanism
- (@pxref{Using Guile Modules,,, guile, Guile reference manual})
- gives the user full control over namespacing: this is needed to avoid
- clashes between, say, the
- @samp{zlib} variable from @samp{licenses.scm} (a @emph{license} value) and the @samp{zlib} variable
- from @samp{compression.scm} (a @emph{package} value).
- @node Other build systems
- @subsection Other build systems
- What we've seen so far covers the majority of packages using a build system
- other than the @code{trivial-build-system}. The latter does not automate anything
- and leaves you to build everything manually. This can be more demanding and we
- won't cover it here for now, but thankfully it is rarely necessary to fall back
- on this system.
- For the other build systems, such as ASDF, Emacs, Perl, Ruby and many more, the
- process is very similar to the GNU build system except for a few specialized
- arguments.
- @xref{Build Systems,,, guix, GNU Guix Reference Manual}, for more
- information on build systems, or check the source code in the
- @samp{$GUIX_CHECKOUT/guix/build} and
- @samp{$GUIX_CHECKOUT/guix/build-system} directories.
- @node Programmable and automated package definition
- @subsection Programmable and automated package definition
- We can't repeat it enough: having a full-fledged programming language at hand
- empowers us in ways that reach far beyond traditional package management.
- Let's illustrate this with some awesome features of Guix!
- @menu
- * Recursive importers::
- * Automatic update::
- * Inheritance::
- @end menu
- @node Recursive importers
- @subsubsection Recursive importers
- You might find some build systems good enough that there is little to do at all
- to write a package, to the point that it becomes repetitive and tedious after a
- while. A @emph{raison d'être} of computers is to replace human beings at those
- boring tasks. So let's tell Guix to do this for us and create the package
- definition of an R package from CRAN (the output is trimmed for conciseness):
- @example
- $ guix import cran --recursive walrus
- (define-public r-mc2d
- ; ...
- (license gpl2+)))
- (define-public r-jmvcore
- ; ...
- (license gpl2+)))
- (define-public r-wrs2
- ; ...
- (license gpl3)))
- (define-public r-walrus
- (package
- (name "r-walrus")
- (version "1.0.3")
- (source
- (origin
- (method url-fetch)
- (uri (cran-uri "walrus" version))
- (sha256
- (base32
- "1nk2glcvy4hyksl5ipq2mz8jy4fss90hx6cq98m3w96kzjni6jjj"))))
- (build-system r-build-system)
- (propagated-inputs
- (list r-ggplot2 r-jmvcore r-r6 r-wrs2))
- (home-page "https://github.com/jamovi/walrus")
- (synopsis "Robust Statistical Methods")
- (description
- "This package provides a toolbox of common robust statistical
- tests, including robust descriptives, robust t-tests, and robust ANOVA.
- It is also available as a module for 'jamovi' (see
- <https://www.jamovi.org> for more information). Walrus is based on the
- WRS2 package by Patrick Mair, which is in turn based on the scripts and
- work of Rand Wilcox. These analyses are described in depth in the book
- 'Introduction to Robust Estimation & Hypothesis Testing'.")
- (license gpl3)))
- @end example
- The recursive importer won't import packages for which Guix already has package
- definitions, except for the very first.
- Not all applications can be packaged this way, only those relying on a select
- number of supported systems. Read about the full list of importers in
- the guix import section of the manual
- (@pxref{Invoking guix import,,, guix, GNU Guix Reference Manual}).
- @node Automatic update
- @subsubsection Automatic update
- Guix can be smart enough to check for updates on systems it knows. It can
- report outdated package definitions with
- @example
- $ guix refresh hello
- @end example
- In most cases, updating a package to a newer version requires little more than
- changing the version number and the checksum. Guix can do that automatically as
- well:
- @example
- $ guix refresh hello --update
- @end example
- @node Inheritance
- @subsubsection Inheritance
- If you've started browsing the existing package definitions, you might have
- noticed that a significant number of them have a @code{inherit} field:
- @lisp
- (define-public adwaita-icon-theme
- (package (inherit gnome-icon-theme)
- (name "adwaita-icon-theme")
- (version "3.26.1")
- (source (origin
- (method url-fetch)
- (uri (string-append "mirror://gnome/sources/" name "/"
- (version-major+minor version) "/"
- name "-" version ".tar.xz"))
- (sha256
- (base32
- "17fpahgh5dyckgz7rwqvzgnhx53cx9kr2xw0szprc6bnqy977fi8"))))
- (native-inputs (list `(,gtk+ "bin")))))
- @end lisp
- All unspecified fields are inherited from the parent package. This is very
- convenient to create alternative packages, for instance with different source,
- version or compilation options.
- @node Getting help
- @subsection Getting help
- Sadly, some applications can be tough to package. Sometimes they need a patch to
- work with the non-standard file system hierarchy enforced by the store.
- Sometimes the tests won't run properly. (They can be skipped but this is not
- recommended.) Other times the resulting package won't be reproducible.
- Should you be stuck, unable to figure out how to fix any sort of packaging
- issue, don't hesitate to ask the community for help.
- See the @uref{https://www.gnu.org/software/guix/contact/, Guix homepage} for information on the mailing lists, IRC, etc.
- @node Conclusion
- @subsection Conclusion
- This tutorial was a showcase of the sophisticated package management that Guix
- boasts. At this point we have mostly restricted this introduction to the
- @code{gnu-build-system} which is a core abstraction layer on which more advanced
- abstractions are based.
- Where do we go from here? Next we ought to dissect the innards of the build
- system by removing all abstractions, using the @code{trivial-build-system}: this
- should give us a thorough understanding of the process before investigating some
- more advanced packaging techniques and edge cases.
- Other features worth exploring are the interactive editing and debugging
- capabilities of Guix provided by the Guile REPL@.
- Those fancy features are completely optional and can wait; now is a good time
- to take a well-deserved break. With what we've introduced here you should be
- well armed to package lots of programs. You can get started right away and
- hopefully we will see your contributions soon!
- @node References
- @subsection References
- @itemize
- @item
- The @uref{https://www.gnu.org/software/guix/manual/en/html_node/Defining-Packages.html, package reference in the manual}
- @item
- @uref{https://gitlab.com/pjotrp/guix-notes/blob/master/HACKING.org, Pjotr’s hacking guide to GNU Guix}
- @item
- @uref{https://www.gnu.org/software/guix/guix-ghm-andreas-20130823.pdf, ``GNU Guix: Package without a scheme!''}, by Andreas Enge
- @end itemize
- @c *********************************************************************
- @node System Configuration
- @chapter System Configuration
- Guix offers a flexible language for declaratively configuring your Guix
- System. This flexibility can at times be overwhelming. The purpose of this
- chapter is to demonstrate some advanced configuration concepts.
- @pxref{System Configuration,,, guix, GNU Guix Reference Manual} for a complete
- reference.
- @menu
- * Auto-Login to a Specific TTY:: Automatically Login a User to a Specific TTY
- * Customizing the Kernel:: Creating and using a custom Linux kernel on Guix System.
- * Guix System Image API:: Customizing images to target specific platforms.
- * Using security keys:: How to use security keys with Guix System.
- * Dynamic DNS mcron job:: Job to update the IP address behind a DuckDNS host name.
- * Connecting to Wireguard VPN:: Connecting to a Wireguard VPN.
- * Customizing a Window Manager:: Handle customization of a Window manager on Guix System.
- * Running Guix on a Linode Server:: Running Guix on a Linode Server.
- * Running Guix on a Kimsufi Server:: Running Guix on a Kimsufi Server.
- * Setting up a bind mount:: Setting up a bind mount in the file-systems definition.
- * Getting substitutes from Tor:: Configuring Guix daemon to get substitutes through Tor.
- * Setting up NGINX with Lua:: Configuring NGINX web-server to load Lua modules.
- * Music Server with Bluetooth Audio:: Headless music player with Bluetooth output.
- @end menu
- @node Auto-Login to a Specific TTY
- @section Auto-Login to a Specific TTY
- While the Guix manual explains auto-login one user to @emph{all} TTYs (
- @pxref{auto-login to TTY,,, guix, GNU Guix Reference Manual}), some
- might prefer a situation, in which one user is logged into one TTY with
- the other TTYs either configured to login different users or no one at
- all. Note that one can auto-login one user to any TTY, but it is
- usually advisable to avoid @code{tty1}, which, by default, is used to
- log warnings and errors.
- Here is how one might set up auto login for one user to one tty:
- @lisp
- (define (auto-login-to-tty config tty user)
- (if (string=? tty (mingetty-configuration-tty config))
- (mingetty-configuration
- (inherit config)
- (auto-login user))
- config))
- (define %my-services
- (modify-services %base-services
- ;; @dots{}
- (mingetty-service-type config =>
- (auto-login-to-tty
- config "tty3" "alice"))))
- (operating-system
- ;; @dots{}
- (services %my-services))
- @end lisp
- One could also @code{compose} (@pxref{Higher-Order Functions,,, guile,
- The Guile Reference Manual}) @code{auto-login-to-tty} to login multiple
- users to multiple ttys.
- Finally, here is a note of caution. Setting up auto login to a TTY,
- means that anyone can turn on your computer and run commands as your
- regular user.
- However, if you have an encrypted root partition, and thus already need
- to enter a passphrase when the system boots, auto-login might be a
- convenient option.
- @node Customizing the Kernel
- @section Customizing the Kernel
- Guix is, at its core, a source based distribution with substitutes
- (@pxref{Substitutes,,, guix, GNU Guix Reference Manual}), and as such building
- packages from their source code is an expected part of regular package
- installations and upgrades. Given this starting point, it makes sense that
- efforts are made to reduce the amount of time spent compiling packages, and
- recent changes and upgrades to the building and distribution of substitutes
- continues to be a topic of discussion within Guix.
- The kernel, while not requiring an overabundance of RAM to build, does take a
- rather long time on an average machine. The official kernel configuration, as
- is the case with many GNU/Linux distributions, errs on the side of
- inclusiveness, and this is really what causes the build to take such a long
- time when the kernel is built from source.
- The Linux kernel, however, can also just be described as a regular old
- package, and as such can be customized just like any other package. The
- procedure is a little bit different, although this is primarily due to the
- nature of how the package definition is written.
- The @code{linux-libre} kernel package definition is actually a procedure which
- creates a package.
- @lisp
- (define* (make-linux-libre* version gnu-revision source supported-systems
- #:key
- (extra-version #f)
- ;; A function that takes an arch and a variant.
- ;; See kernel-config for an example.
- (configuration-file #f)
- (defconfig "defconfig")
- (extra-options %default-extra-linux-options))
- ...)
- @end lisp
- The current @code{linux-libre} package is for the 5.15.x series, and is
- declared like this:
- @lisp
- (define-public linux-libre-5.15
- (make-linux-libre* linux-libre-5.15-version
- linux-libre-5.15-gnu-revision
- linux-libre-5.15-source
- '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux" "riscv64-linux")
- #:configuration-file kernel-config))
- @end lisp
- Any keys which are not assigned values inherit their default value from the
- @code{make-linux-libre} definition. When comparing the two snippets above,
- notice the code comment that refers to @code{#:configuration-file}. Because of
- this, it is not actually easy to include a custom kernel configuration from the
- definition, but don't worry, there are other ways to work with what we do have.
- There are two ways to create a kernel with a custom kernel configuration. The
- first is to provide a standard @file{.config} file during the build process by
- including an actual @file{.config} file as a native input to our custom
- kernel. The following is a snippet from the custom @code{'configure} phase of
- the @code{make-linux-libre} package definition:
- @lisp
- (let ((build (assoc-ref %standard-phases 'build))
- (config (assoc-ref (or native-inputs inputs) "kconfig")))
- ;; Use a custom kernel configuration file or a default
- ;; configuration file.
- (if config
- (begin
- (copy-file config ".config")
- (chmod ".config" #o666))
- (invoke "make" ,defconfig)))
- @end lisp
- Below is a sample kernel package. The @code{linux-libre} package is nothing
- special and can be inherited from and have its fields overridden like any
- other package:
- @lisp
- (define-public linux-libre/E2140
- (package
- (inherit linux-libre)
- (native-inputs
- `(("kconfig" ,(local-file "E2140.config"))
- ,@@(alist-delete "kconfig"
- (package-native-inputs linux-libre))))))
- @end lisp
- In the same directory as the file defining @code{linux-libre-E2140} is a file
- named @file{E2140.config}, which is an actual kernel configuration file. The
- @code{defconfig} keyword of @code{make-linux-libre} is left blank here, so the
- only kernel configuration in the package is the one which was included in the
- @code{native-inputs} field.
- The second way to create a custom kernel is to pass a new value to the
- @code{extra-options} keyword of the @code{make-linux-libre} procedure. The
- @code{extra-options} keyword works with another function defined right below
- it:
- @lisp
- (define %default-extra-linux-options
- `(;; https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00039.html
- ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #true)
- ;; Modules required for initrd:
- ("CONFIG_NET_9P" . m)
- ("CONFIG_NET_9P_VIRTIO" . m)
- ("CONFIG_VIRTIO_BLK" . m)
- ("CONFIG_VIRTIO_NET" . m)
- ("CONFIG_VIRTIO_PCI" . m)
- ("CONFIG_VIRTIO_BALLOON" . m)
- ("CONFIG_VIRTIO_MMIO" . m)
- ("CONFIG_FUSE_FS" . m)
- ("CONFIG_CIFS" . m)
- ("CONFIG_9P_FS" . m)))
- (define (config->string options)
- (string-join (map (match-lambda
- ((option . 'm)
- (string-append option "=m"))
- ((option . #true)
- (string-append option "=y"))
- ((option . #false)
- (string-append option "=n")))
- options)
- "\n"))
- @end lisp
- And in the custom configure script from the `make-linux-libre` package:
- @lisp
- ;; Appending works even when the option wasn't in the
- ;; file. The last one prevails if duplicated.
- (let ((port (open-file ".config" "a"))
- (extra-configuration ,(config->string extra-options)))
- (display extra-configuration port)
- (close-port port))
- (invoke "make" "oldconfig")
- @end lisp
- So by not providing a configuration-file the @file{.config} starts blank, and
- then we write into it the collection of flags that we want. Here's another
- custom kernel:
- @lisp
- (define %macbook41-full-config
- (append %macbook41-config-options
- %file-systems
- %efi-support
- %emulation
- (@@@@ (gnu packages linux) %default-extra-linux-options)))
- (define-public linux-libre-macbook41
- ;; XXX: Access the internal 'make-linux-libre*' procedure, which is
- ;; private and unexported, and is liable to change in the future.
- ((@@@@ (gnu packages linux) make-linux-libre*)
- (@@@@ (gnu packages linux) linux-libre-version)
- (@@@@ (gnu packages linux) linux-libre-gnu-revision)
- (@@@@ (gnu packages linux) linux-libre-source)
- '("x86_64-linux")
- #:extra-version "macbook41"
- #:extra-options %macbook41-config-options))
- @end lisp
- In the above example @code{%file-systems} is a collection of flags enabling
- different file system support, @code{%efi-support} enables EFI support and
- @code{%emulation} enables a x86_64-linux machine to act in 32-bit mode also.
- @code{%default-extra-linux-options} are the ones quoted above, which had to be
- added in since they were replaced in the @code{extra-options} keyword.
- This all sounds like it should be doable, but how does one even know which
- modules are required for a particular system? Two places that can be helpful
- in trying to answer this question is the
- @uref{https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Kernel, Gentoo
- Handbook} and the
- @uref{https://www.kernel.org/doc/html/latest/admin-guide/README.html?highlight=localmodconfig,
- documentation from the kernel itself}. From the kernel documentation, it
- seems that @code{make localmodconfig} is the command we want.
- In order to actually run @code{make localmodconfig} we first need to get and
- unpack the kernel source code:
- @example shell
- tar xf $(guix build linux-libre --source)
- @end example
- Once inside the directory containing the source code run @code{touch .config}
- to create an initial, empty @file{.config} to start with. @code{make
- localmodconfig} works by seeing what you already have in @file{.config} and
- letting you know what you're missing. If the file is blank then you're
- missing everything. The next step is to run:
- @example shell
- guix shell -D linux-libre -- make localmodconfig
- @end example
- and note the output. Do note that the @file{.config} file is still empty.
- The output generally contains two types of warnings. The first start with
- "WARNING" and can actually be ignored in our case. The second read:
- @example shell
- module pcspkr did not have configs CONFIG_INPUT_PCSPKR
- @end example
- For each of these lines, copy the @code{CONFIG_XXXX_XXXX} portion into the
- @file{.config} in the directory, and append @code{=m}, so in the end it looks
- like this:
- @example shell
- CONFIG_INPUT_PCSPKR=m
- CONFIG_VIRTIO=m
- @end example
- After copying all the configuration options, run @code{make localmodconfig}
- again to make sure that you don't have any output starting with ``module''.
- After all of these machine specific modules there are a couple more left that
- are also needed. @code{CONFIG_MODULES} is necessary so that you can build and
- load modules separately and not have everything built into the kernel.
- @code{CONFIG_BLK_DEV_SD} is required for reading from hard drives. It is
- possible that there are other modules which you will need.
- This post does not aim to be a guide to configuring your own kernel however,
- so if you do decide to build a custom kernel you'll have to seek out other
- guides to create a kernel which is just right for your needs.
- The second way to setup the kernel configuration makes more use of Guix's
- features and allows you to share configuration segments between different
- kernels. For example, all machines using EFI to boot have a number of EFI
- configuration flags that they need. It is likely that all the kernels will
- share a list of file systems to support. By using variables it is easier to
- see at a glance what features are enabled and to make sure you don't have
- features in one kernel but missing in another.
- Left undiscussed however, is Guix's initrd and its customization. It is
- likely that you'll need to modify the initrd on a machine using a custom
- kernel, since certain modules which are expected to be built may not be
- available for inclusion into the initrd.
- @node Guix System Image API
- @section Guix System Image API
- Historically, Guix System is centered around an @code{operating-system}
- structure. This structure contains various fields ranging from the
- bootloader and kernel declaration to the services to install.
- Depending on the target machine, that can go from a standard
- @code{x86_64} machine to a small ARM single board computer such as the
- Pine64, the image constraints can vary a lot. The hardware
- manufacturers will impose different image formats with various partition
- sizes and offsets.
- To create images suitable for all those machines, a new abstraction is
- necessary: that's the goal of the @code{image} record. This record
- contains all the required information to be transformed into a
- standalone image, that can be directly booted on any target machine.
- @lisp
- (define-record-type* <image>
- image make-image
- image?
- (name image-name ;symbol
- (default #f))
- (format image-format) ;symbol
- (target image-target
- (default #f))
- (size image-size ;size in bytes as integer
- (default 'guess))
- (operating-system image-operating-system ;<operating-system>
- (default #f))
- (partitions image-partitions ;list of <partition>
- (default '()))
- (compression? image-compression? ;boolean
- (default #t))
- (volatile-root? image-volatile-root? ;boolean
- (default #t))
- (substitutable? image-substitutable? ;boolean
- (default #t)))
- @end lisp
- This record contains the operating-system to instantiate. The
- @code{format} field defines the image type and can be @code{efi-raw},
- @code{qcow2} or @code{iso9660} for instance. In the future, it could be
- extended to @code{docker} or other image types.
- A new directory in the Guix sources is dedicated to images definition. For now
- there are four files:
- @itemize @bullet
- @item @file{gnu/system/images/hurd.scm}
- @item @file{gnu/system/images/pine64.scm}
- @item @file{gnu/system/images/novena.scm}
- @item @file{gnu/system/images/pinebook-pro.scm}
- @end itemize
- Let's have a look to @file{pine64.scm}. It contains the
- @code{pine64-barebones-os} variable which is a minimal definition of an
- operating-system dedicated to the @b{Pine A64 LTS} board.
- @lisp
- (define pine64-barebones-os
- (operating-system
- (host-name "vignemale")
- (timezone "Europe/Paris")
- (locale "en_US.utf8")
- (bootloader (bootloader-configuration
- (bootloader u-boot-pine64-lts-bootloader)
- (targets '("/dev/vda"))))
- (initrd-modules '())
- (kernel linux-libre-arm64-generic)
- (file-systems (cons (file-system
- (device (file-system-label "my-root"))
- (mount-point "/")
- (type "ext4"))
- %base-file-systems))
- (services (cons (service agetty-service-type
- (agetty-configuration
- (extra-options '("-L")) ; no carrier detect
- (baud-rate "115200")
- (term "vt100")
- (tty "ttyS0")))
- %base-services))))
- @end lisp
- The @code{kernel} and @code{bootloader} fields are pointing to packages
- dedicated to this board.
- Right below, the @code{pine64-image-type} variable is also defined.
- @lisp
- (define pine64-image-type
- (image-type
- (name 'pine64-raw)
- (constructor (cut image-with-os arm64-disk-image <>))))
- @end lisp
- It's using a record we haven't talked about yet, the @code{image-type} record,
- defined this way:
- @lisp
- (define-record-type* <image-type>
- image-type make-image-type
- image-type?
- (name image-type-name) ;symbol
- (constructor image-type-constructor)) ;<operating-system> -> <image>
- @end lisp
- The main purpose of this record is to associate a name to a procedure
- transforming an @code{operating-system} to an image. To understand why
- it is necessary, let's have a look to the command producing an image
- from an @code{operating-system} configuration file:
- @example
- guix system image my-os.scm
- @end example
- This command expects an @code{operating-system} configuration but how
- should we indicate that we want an image targeting a Pine64 board? We
- need to provide an extra information, the @code{image-type}, by passing
- the @code{--image-type} or @code{-t} flag, this way:
- @example
- guix system image --image-type=pine64-raw my-os.scm
- @end example
- This @code{image-type} parameter points to the @code{pine64-image-type}
- defined above. Hence, the @code{operating-system} declared in
- @code{my-os.scm} will be applied the @code{(cut image-with-os
- arm64-disk-image <>)} procedure to turn it into an image.
- The resulting image looks like:
- @lisp
- (image
- (format 'disk-image)
- (target "aarch64-linux-gnu")
- (operating-system my-os)
- (partitions
- (list (partition
- (inherit root-partition)
- (offset root-offset)))))
- @end lisp
- which is the aggregation of the @code{operating-system} defined in
- @code{my-os.scm} to the @code{arm64-disk-image} record.
- But enough Scheme madness. What does this image API bring to the Guix user?
- One can run:
- @example
- mathieu@@cervin:~$ guix system --list-image-types
- The available image types are:
- - unmatched-raw
- - rock64-raw
- - pinebook-pro-raw
- - pine64-raw
- - novena-raw
- - hurd-raw
- - hurd-qcow2
- - qcow2
- - iso9660
- - uncompressed-iso9660
- - tarball
- - efi-raw
- - mbr-raw
- - docker
- - wsl2
- - raw-with-offset
- - efi32-raw
- @end example
- and by writing an @code{operating-system} file based on
- @code{pine64-barebones-os}, you can customize your image to your
- preferences in a file (@file{my-pine-os.scm}) like this:
- @lisp
- (use-modules (gnu services linux)
- (gnu system images pine64))
- (let ((base-os pine64-barebones-os))
- (operating-system
- (inherit base-os)
- (timezone "America/Indiana/Indianapolis")
- (services
- (cons
- (service earlyoom-service-type
- (earlyoom-configuration
- (prefer-regexp "icecat|chromium")))
- (operating-system-user-services base-os)))))
- @end lisp
- run:
- @example
- guix system image --image-type=pine64-raw my-pine-os.scm
- @end example
- or,
- @example
- guix system image --image-type=hurd-raw my-hurd-os.scm
- @end example
- to get an image that can be written directly to a hard drive and booted
- from.
- Without changing anything to @code{my-hurd-os.scm}, calling:
- @example
- guix system image --image-type=hurd-qcow2 my-hurd-os.scm
- @end example
- will instead produce a Hurd QEMU image.
- @node Using security keys
- @section Using security keys
- @cindex 2FA, two-factor authentication
- @cindex U2F, Universal 2nd Factor
- @cindex security key, configuration
- The use of security keys can improve your security by providing a second
- authentication source that cannot be easily stolen or copied, at least
- for a remote adversary (something that you have), to the main secret (a
- passphrase -- something that you know), reducing the risk of
- impersonation.
- The example configuration detailed below showcases what minimal
- configuration needs to be made on your Guix System to allow the use of a
- Yubico security key. It is hoped the configuration can be useful for
- other security keys as well, with minor adjustments.
- @subsection Configuration for use as a two-factor authenticator (2FA)
- To be usable, the udev rules of the system should be extended with
- key-specific rules. The following shows how to extend your udev rules
- with the @file{lib/udev/rules.d/70-u2f.rules} udev rule file provided by
- the @code{libfido2} package from the @code{(gnu packages
- security-token)} module and add your user to the @samp{"plugdev"} group
- it uses:
- @lisp
- (use-package-modules ... security-token ...)
- ...
- (operating-system
- ...
- (users (cons* (user-account
- (name "your-user")
- (group "users")
- (supplementary-groups
- '("wheel" "netdev" "audio" "video"
- "plugdev")) ;<- added system group
- (home-directory "/home/your-user"))
- %base-user-accounts))
- ...
- (services
- (cons*
- ...
- (udev-rules-service 'fido2 libfido2 #:groups '("plugdev")))))
- @end lisp
- After re-configuring your system and re-logging in your graphical
- session so that the new group is in effect for your user, you can verify
- that your key is usable by launching:
- @example
- guix shell ungoogled-chromium -- chromium chrome://settings/securityKeys
- @end example
- and validating that the security key can be reset via the ``Reset your
- security key'' menu. If it works, congratulations, your security key is
- ready to be used with applications supporting two-factor authentication
- (2FA).
- @subsection Disabling OTP code generation for a Yubikey
- @cindex disabling yubikey OTP
- If you use a Yubikey security key and are irritated by the spurious OTP
- codes it generates when inadvertently touching the key (e.g. causing you
- to become a spammer in the @samp{#guix} channel when discussing from
- your favorite IRC client!), you can disable it via the following
- @command{ykman} command:
- @example
- guix shell python-yubikey-manager -- ykman config usb --force --disable OTP
- @end example
- Alternatively, you could use the @command{ykman-gui} command provided by
- the @code{yubikey-manager-qt} package and either wholly disable the
- @samp{OTP} application for the USB interface or, from the
- @samp{Applications -> OTP} view, delete the slot 1 configuration, which
- comes pre-configured with the Yubico OTP application.
- @subsection Requiring a Yubikey to open a KeePassXC database
- @cindex yubikey, keepassxc integration
- The KeePassXC password manager application has support for Yubikeys, but
- it requires installing a udev rules for your Guix System and some
- configuration of the Yubico OTP application on the key.
- The necessary udev rules file comes from the
- @code{yubikey-personalization} package, and can be installed like:
- @lisp
- (use-package-modules ... security-token ...)
- ...
- (operating-system
- ...
- (services
- (cons*
- ...
- (udev-rules-service 'yubikey yubikey-personalization))))
- @end lisp
- After reconfiguring your system (and reconnecting your Yubikey), you'll
- then want to configure the OTP challenge/response application of your
- Yubikey on its slot 2, which is what KeePassXC uses. It's easy to do so
- via the Yubikey Manager graphical configuration tool, which can be
- invoked with:
- @example
- guix shell yubikey-manager-qt -- ykman-gui
- @end example
- First, ensure @samp{OTP} is enabled under the @samp{Interfaces} tab,
- then navigate to @samp{Applications -> OTP}, and click the
- @samp{Configure} button under the @samp{Long Touch (Slot 2)} section.
- Select @samp{Challenge-response}, input or generate a secret key, and
- click the @samp{Finish} button. If you have a second Yubikey you'd like
- to use as a backup, you should configure it the same way, using the
- @emph{same} secret key.
- Your Yubikey should now be detected by KeePassXC. It can be added to a
- database by navigating to KeePassXC's @samp{Database -> Database
- Security...} menu, then clicking the @samp{Add additional
- protection...} button, then @samp{Add Challenge-Response}, selecting the
- security key from the drop-down menu and clicking the @samp{OK} button
- to complete the setup.
- @node Dynamic DNS mcron job
- @section Dynamic DNS mcron job
- @cindex dynamic DNS, DDNS
- If your @acronym{ISP, Internet Service Provider} only provides dynamic
- IP addresses, it can be useful to setup a dynamic @acronym{DNS, Domain
- Name System} (also known as @acronym{DDNS, Dynamic DNS}) service to
- associate a static host name to a public but dynamic (often changing) IP
- address. There are multiple existing services that can be used for
- this; in the following mcron job, @url{https://duckdns.org, DuckDNS} is
- used. It should also work with other dynamic DNS services that offer a
- similar interface to update the IP address, such as
- @url{https://freedns.afraid.org/}, with minor adjustments.
- The mcron job is provided below, where @var{DOMAIN} should be
- substituted for your own domain prefix, and the DuckDNS provided token
- associated to @var{DOMAIN} added to the
- @file{/etc/duckdns/@var{DOMAIN}.token} file.
- @lisp
- (define duckdns-job
- ;; Update personal domain IP every 5 minutes.
- #~(job '(next-minute (range 0 60 5))
- #$(program-file
- "duckdns-update"
- (with-extensions (list guile-gnutls) ;required by (web client)
- #~(begin
- (use-modules (ice-9 textual-ports)
- (web client))
- (let ((token (string-trim-both
- (call-with-input-file "/etc/duckdns/@var{DOMAIN}.token"
- get-string-all)))
- (query-template (string-append "https://www.duckdns.org/"
- "update?domains=@var{DOMAIN}"
- "&token=~a&ip=")))
- (http-get (format #f query-template token))))))
- "duckdns-update"
- #:user "nobody"))
- @end lisp
- The job then needs to be added to the list of mcron jobs for your
- system, using something like:
- @lisp
- (operating-system
- (services
- (cons* (service mcron-service-type
- (mcron-configuration
- (jobs (list duckdns-job ...))))
- ...
- %base-services)))
- @end lisp
- @node Connecting to Wireguard VPN
- @section Connecting to Wireguard VPN
- To connect to a Wireguard VPN server you need the kernel module to be
- loaded in memory and a package providing networking tools that support
- it (e.g. @code{wireguard-tools} or @code{network-manager}).
- Here is a configuration example for Linux-Libre < 5.6, where the module
- is out of tree and need to be loaded manually---following revisions of
- the kernel have it built-in and so don't need such configuration:
- @lisp
- (use-modules (gnu))
- (use-service-modules desktop)
- (use-package-modules vpn)
- (operating-system
- ;; …
- (services (cons (simple-service 'wireguard-module
- kernel-module-loader-service-type
- '("wireguard"))
- %desktop-services))
- (packages (cons wireguard-tools %base-packages))
- (kernel-loadable-modules (list wireguard-linux-compat)))
- @end lisp
- After reconfiguring and restarting your system you can either use
- Wireguard tools or NetworkManager to connect to a VPN server.
- @subsection Using Wireguard tools
- To test your Wireguard setup it is convenient to use @command{wg-quick}.
- Just give it a configuration file @command{wg-quick up ./wg0.conf}; or
- put that file in @file{/etc/wireguard} and run @command{wg-quick up wg0}
- instead.
- @quotation Note
- Be warned that the author described this command as a: “[…] very quick
- and dirty bash script […]”.
- @end quotation
- @subsection Using NetworkManager
- Thanks to NetworkManager support for Wireguard we can connect to our VPN
- using @command{nmcli} command. Up to this point this guide assumes that
- you're using Network Manager service provided by
- @code{%desktop-services}. Ortherwise you need to adjust your services
- list to load @code{network-manager-service-type} and reconfigure your
- Guix system.
- To import your VPN configuration execute nmcli import command:
- @example shell
- # nmcli connection import type wireguard file wg0.conf
- Connection 'wg0' (edbee261-aa5a-42db-b032-6c7757c60fde) successfully added
- @end example
- This will create a configuration file in
- @file{/etc/NetworkManager/wg0.nmconnection}. Next connect to the
- Wireguard server:
- @example shell
- $ nmcli connection up wg0
- Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/6)
- @end example
- By default NetworkManager will connect automatically on system boot. To
- change that behaviour you need to edit your config:
- @example shell
- # nmcli connection modify wg0 connection.autoconnect no
- @end example
- For more specific information about NetworkManager and wireguard
- @uref{https://blogs.gnome.org/thaller/2019/03/15/wireguard-in-networkmanager/,see
- this post by thaller}.
- @node Customizing a Window Manager
- @section Customizing a Window Manager
- @cindex wm
- @menu
- * StumpWM::
- * Session lock::
- @end menu
- @node StumpWM
- @subsection StumpWM
- @cindex stumpwm
- You could install StumpWM with a Guix system by adding
- @code{stumpwm} and optionally @code{`(,stumpwm "lib")}
- packages to a system configuration file, e.g.@: @file{/etc/config.scm}.
- An example configuration can look like this:
- @lisp
- (use-modules (gnu))
- (use-package-modules wm)
- (operating-system
- ;; …
- (packages (append (list sbcl stumpwm `(,stumpwm "lib"))
- %base-packages)))
- @end lisp
- @cindex stumpwm fonts
- By default StumpWM uses X11 fonts, which could be small or pixelated on
- your system. You could fix this by installing StumpWM contrib Lisp
- module @code{sbcl-ttf-fonts}, adding it to Guix system packages:
- @lisp
- (use-modules (gnu))
- (use-package-modules fonts wm)
- (operating-system
- ;; …
- (packages (append (list sbcl stumpwm `(,stumpwm "lib"))
- sbcl-ttf-fonts font-dejavu %base-packages)))
- @end lisp
- Then you need to add the following code to a StumpWM configuration file
- @file{~/.stumpwm.d/init.lisp}:
- @lisp
- (require :ttf-fonts)
- (setf xft:*font-dirs* '("/run/current-system/profile/share/fonts/"))
- (setf clx-truetype:+font-cache-filename+ (concat (getenv "HOME") "/.fonts/font-cache.sexp"))
- (xft:cache-fonts)
- (set-font (make-instance 'xft:font :family "DejaVu Sans Mono" :subfamily "Book" :size 11))
- @end lisp
- @node Session lock
- @subsection Session lock
- @cindex sessionlock
- Depending on your environment, locking the screen of your session might come built in
- or it might be something you have to set up yourself. If you use a desktop environment
- like GNOME or KDE, it's usually built in. If you use a plain window manager like
- StumpWM or EXWM, you might have to set it up yourself.
- @menu
- * Xorg::
- @end menu
- @node Xorg
- @subsubsection Xorg
- If you use Xorg, you can use the utility
- @uref{https://www.mankier.com/1/xss-lock, xss-lock} to lock the screen of your session.
- xss-lock is triggered by DPMS which since Xorg 1.8 is auto-detected and enabled if
- ACPI is also enabled at kernel runtime.
- To use xss-lock, you can simple execute it and put it into the background before
- you start your window manager from e.g. your @file{~/.xsession}:
- @example
- xss-lock -- slock &
- exec stumpwm
- @end example
- In this example, xss-lock uses @code{slock} to do the actual locking of the screen when
- it determines it's appropriate, like when you suspend your device.
- For slock to be allowed to be a screen locker for the graphical session, it needs to
- be made setuid-root so it can authenticate users, and it needs a PAM service. This
- can be achieved by adding the following service to your @file{config.scm}:
- @lisp
- (service screen-locker-services-type
- (screen-locker-configuration
- (name "slock")
- (program (file-append slock "/bin/slock"))))
- @end lisp
- If you manually lock your screen, e.g. by directly calling slock when you want to lock
- your screen but not suspend it, it's a good idea to notify xss-lock about this so no
- confusion occurs. This can be done by executing @code{xset s activate} immediately
- before you execute slock.
- @node Running Guix on a Linode Server
- @section Running Guix on a Linode Server
- @cindex linode, Linode
- To run Guix on a server hosted by @uref{https://www.linode.com, Linode},
- start with a recommended Debian server. We recommend using the default
- distro as a way to bootstrap Guix. Create your SSH keys.
- @example
- ssh-keygen
- @end example
- Be sure to add your SSH key for easy login to the remote server.
- This is trivially done via Linode's graphical interface for adding
- SSH keys. Go to your profile and click add SSH Key.
- Copy into it the output of:
- @example
- cat ~/.ssh/<username>_rsa.pub
- @end example
- Power the Linode down.
- In the Linode's Storage tab, resize the Debian disk to be smaller.
- 30 GB free space is recommended. Then click "Add a disk", and fill
- out the form with the following:
- @itemize @bullet
- @item
- Label: "Guix"
- @item
- Filesystem: ext4
- @item
- Set it to the remaining size
- @end itemize
- In the Configurations tab, press "Edit" on the default Debian profile.
- Under "Block Device Assignment" click "Add a Device". It should be
- @file{/dev/sdc} and you can select the "Guix" disk. Save Changes.
- Now "Add a Configuration", with the following:
- @itemize @bullet
- @item
- Label: Guix
- @item
- Kernel:GRUB 2 (it's at the bottom! This step is @b{IMPORTANT!})
- @item
- Block device assignment:
- @item
- @file{/dev/sda}: Guix
- @item
- @file{/dev/sdb}: swap
- @item
- Root device: @file{/dev/sda}
- @item
- Turn off all the filesystem/boot helpers
- @end itemize
- Now power it back up, booting with the Debian configuration. Once it's
- running, ssh to your server via @code{ssh
- root@@@var{<your-server-IP-here>}}. (You can find your server IP address in
- your Linode Summary section.) Now you can run the "install guix from
- @pxref{Binary Installation,,, guix, GNU Guix}" steps:
- @example
- sudo apt-get install gpg
- wget https://sv.gnu.org/people/viewgpg.php?user_id=15145 -qO - | gpg --import -
- wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
- chmod +x guix-install.sh
- ./guix-install.sh
- guix pull
- @end example
- Now it's time to write out a config for the server. The key information
- is below. Save the resulting file as @file{guix-config.scm}.
- @lisp
- (use-modules (gnu)
- (guix modules))
- (use-service-modules networking
- ssh)
- (use-package-modules admin
- certs
- package-management
- ssh
- tls)
- (operating-system
- (host-name "my-server")
- (timezone "America/New_York")
- (locale "en_US.UTF-8")
- ;; This goofy code will generate the grub.cfg
- ;; without installing the grub bootloader on disk.
- (bootloader (bootloader-configuration
- (bootloader
- (bootloader
- (inherit grub-bootloader)
- (installer #~(const #true))))))
- (file-systems (cons (file-system
- (device "/dev/sda")
- (mount-point "/")
- (type "ext4"))
- %base-file-systems))
- (swap-devices (list "/dev/sdb"))
- (initrd-modules (cons "virtio_scsi" ; Needed to find the disk
- %base-initrd-modules))
- (users (cons (user-account
- (name "janedoe")
- (group "users")
- ;; Adding the account to the "wheel" group
- ;; makes it a sudoer.
- (supplementary-groups '("wheel"))
- (home-directory "/home/janedoe"))
- %base-user-accounts))
- (packages (cons* nss-certs ;for HTTPS access
- openssh-sans-x
- %base-packages))
- (services (cons*
- (service dhcp-client-service-type)
- (service openssh-service-type
- (openssh-configuration
- (openssh openssh-sans-x)
- (password-authentication? #false)
- (authorized-keys
- `(("janedoe" ,(local-file "janedoe_rsa.pub"))
- ("root" ,(local-file "janedoe_rsa.pub"))))))
- %base-services)))
- @end lisp
- Replace the following fields in the above configuration:
- @lisp
- (host-name "my-server") ; replace with your server name
- ; if you chose a linode server outside the U.S., then
- ; use tzselect to find a correct timezone string
- (timezone "America/New_York") ; if needed replace timezone
- (name "janedoe") ; replace with your username
- ("janedoe" ,(local-file "janedoe_rsa.pub")) ; replace with your ssh key
- ("root" ,(local-file "janedoe_rsa.pub")) ; replace with your ssh key
- @end lisp
- The last line in the above example lets you log into the server as root
- and set the initial root password (see the note at the end of this
- recipe about root login). After you have done this, you may
- delete that line from your configuration and reconfigure to prevent root
- login.
- Copy your ssh public key (eg: @file{~/.ssh/id_rsa.pub}) as
- @file{@var{<your-username-here>}_rsa.pub} and put
- @file{guix-config.scm} in the same directory. In a new terminal run
- these commands.
- @example
- sftp root@@<remote server ip address>
- put /path/to/files/<username>_rsa.pub .
- put /path/to/files/guix-config.scm .
- @end example
- In your first terminal, mount the guix drive:
- @example
- mkdir /mnt/guix
- mount /dev/sdc /mnt/guix
- @end example
- Due to the way we set up the bootloader section of the guix-config.scm,
- only the grub configuration file will be installed. So, we need to copy
- over some of the other GRUB stuff already installed on the Debian system:
- @example
- mkdir -p /mnt/guix/boot/grub
- cp -r /boot/grub/* /mnt/guix/boot/grub/
- @end example
- Now initialize the Guix installation:
- @example
- guix system init guix-config.scm /mnt/guix
- @end example
- Ok, power it down!
- Now from the Linode console, select boot and select "Guix".
- Once it boots, you should be able to log in via SSH! (The server config
- will have changed though.) You may encounter an error like:
- @example
- $ ssh root@@<server ip address>
- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
- IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
- Someone could be eavesdropping on you right now (man-in-the-middle attack)!
- It is also possible that a host key has just been changed.
- The fingerprint for the ECDSA key sent by the remote host is
- SHA256:0B+wp33w57AnKQuHCvQP0+ZdKaqYrI/kyU7CfVbS7R4.
- Please contact your system administrator.
- Add correct host key in /home/joshua/.ssh/known_hosts to get rid of this message.
- Offending ECDSA key in /home/joshua/.ssh/known_hosts:3
- ECDSA host key for 198.58.98.76 has changed and you have requested strict checking.
- Host key verification failed.
- @end example
- Either delete @file{~/.ssh/known_hosts} file, or delete the offending line
- starting with your server IP address.
- Be sure to set your password and root's password.
- @example
- ssh root@@<remote ip address>
- passwd ; for the root password
- passwd <username> ; for the user password
- @end example
- You may not be able to run the above commands at this point. If you
- have issues remotely logging into your linode box via SSH, then you may
- still need to set your root and user password initially by clicking on
- the ``Launch Console'' option in your linode. Choose the ``Glish''
- instead of ``Weblish''. Now you should be able to ssh into the machine.
- Hooray! At this point you can shut down the server, delete the
- Debian disk, and resize the Guix to the rest of the size.
- Congratulations!
- By the way, if you save it as a disk image right at this point, you'll
- have an easy time spinning up new Guix images! You may need to
- down-size the Guix image to 6144MB, to save it as an image. Then you
- can resize it again to the max size.
- @node Running Guix on a Kimsufi Server
- @section Running Guix on a Kimsufi Server
- @cindex kimsufi, Kimsufi, OVH
- To run Guix on a server hosted by @uref{https://www.kimsufi.com/,
- Kimsufi}, click on the netboot tab then select rescue64-pro and restart.
- OVH will email you the credentials required to ssh into a Debian system.
- Now you can run the "install guix from @pxref{Binary Installation,,,
- guix, GNU Guix}" steps:
- @example
- wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
- chmod +x guix-install.sh
- ./guix-install.sh
- guix pull
- @end example
- Partition the drives and format them, first stop the raid array:
- @example
- mdadm --stop /dev/md127
- mdadm --zero-superblock /dev/sda2 /dev/sdb2
- @end example
- Then wipe the disks and set up the partitions, we will create
- a RAID 1 array.
- @example
- wipefs -a /dev/sda
- wipefs -a /dev/sdb
- parted /dev/sda --align=opt -s -m -- mklabel gpt
- parted /dev/sda --align=opt -s -m -- \
- mkpart bios_grub 1049kb 512MiB \
- set 1 bios_grub on
- parted /dev/sda --align=opt -s -m -- \
- mkpart primary 512MiB -512MiB
- set 2 raid on
- parted /dev/sda --align=opt -s -m -- mkpart primary linux-swap 512MiB 100%
- parted /dev/sdb --align=opt -s -m -- mklabel gpt
- parted /dev/sdb --align=opt -s -m -- \
- mkpart bios_grub 1049kb 512MiB \
- set 1 bios_grub on
- parted /dev/sdb --align=opt -s -m -- \
- mkpart primary 512MiB -512MiB \
- set 2 raid on
- parted /dev/sdb --align=opt -s -m -- mkpart primary linux-swap 512MiB 100%
- @end example
- Create the array:
- @example
- mdadm --create /dev/md127 --level=1 --raid-disks=2 \
- --metadata=0.90 /dev/sda2 /dev/sdb2
- @end example
- Now create file systems on the relevant partitions, first the boot
- partitions:
- @example
- mkfs.ext4 /dev/sda1
- mkfs.ext4 /dev/sdb1
- @end example
- Then the root partition:
- @example
- mkfs.ext4 /dev/md127
- @end example
- Initialize the swap partitions:
- @example
- mkswap /dev/sda3
- swapon /dev/sda3
- mkswap /dev/sdb3
- swapon /dev/sdb3
- @end example
- Mount the guix drive:
- @example
- mkdir /mnt/guix
- mount /dev/md127 /mnt/guix
- @end example
- Now is time to write an operating system declaration @file{os.scm} file;
- here is a sample:
- @lisp
- (use-modules (gnu) (guix))
- (use-service-modules networking ssh vpn virtualization sysctl admin mcron)
- (use-package-modules ssh certs tls tmux vpn virtualization)
- (operating-system
- (host-name "kimsufi")
- (bootloader (bootloader-configuration
- (bootloader grub-bootloader)
- (targets (list "/dev/sda" "/dev/sdb"))
- (terminal-outputs '(console))))
- ;; Add a kernel module for RAID-1 (aka. "mirror").
- (initrd-modules (cons* "raid1" %base-initrd-modules))
- (mapped-devices
- (list (mapped-device
- (source (list "/dev/sda2" "/dev/sdb2"))
- (target "/dev/md127")
- (type raid-device-mapping))))
- (swap-devices
- (list (swap-space
- (target "/dev/sda3"))
- (swap-space
- (target "/dev/sdb3"))))
- (issue
- ;; Default contents for /etc/issue.
- "\
- This is the GNU system at Kimsufi. Welcome.\n")
- (file-systems (cons* (file-system
- (mount-point "/")
- (device "/dev/md127")
- (type "ext4")
- (dependencies mapped-devices))
- %base-file-systems))
- (users (cons (user-account
- (name "guix")
- (comment "guix")
- (group "users")
- (supplementary-groups '("wheel"))
- (home-directory "/home/guix"))
- %base-user-accounts))
- (sudoers-file
- (plain-file "sudoers" "\
- root ALL=(ALL) ALL
- %wheel ALL=(ALL) ALL
- guix ALL=(ALL) NOPASSWD:ALL\n"))
- ;; Globally-installed packages.
- (packages (cons* tmux nss-certs gnutls wireguard-tools %base-packages))
- (services
- (cons*
- (service static-networking-service-type
- (list (static-networking
- (addresses (list (network-address
- (device "enp3s0")
- (value "@var{server-ip-address}/24"))))
- (routes (list (network-route
- (destination "default")
- (gateway "@var{server-gateway}"))))
- (name-servers '("213.186.33.99")))))
- (service unattended-upgrade-service-type)
- (service openssh-service-type
- (openssh-configuration
- (openssh openssh-sans-x)
- (permit-root-login #f)
- (authorized-keys
- `(("guix" ,(plain-file "@var{ssh-key-name.pub}"
- "@var{ssh-public-key-content}"))))))
- (modify-services %base-services
- (sysctl-service-type
- config =>
- (sysctl-configuration
- (settings (append '(("net.ipv6.conf.all.autoconf" . "0")
- ("net.ipv6.conf.all.accept_ra" . "0"))
- %default-sysctl-settings))))))))
- @end lisp
- Don't forget to substitute the @var{server-ip-address},
- @var{server-gateway}, @var{ssh-key-name} and
- @var{ssh-public-key-content} variables with your own values.
- The gateway is the last usable IP in your block so if you have a server
- with an IP of @samp{37.187.79.10} then its gateway will be
- @samp{37.187.79.254}.
- Transfer your operating system declaration @file{os.scm} file on the
- server via the @command{scp} or @command{sftp} commands.
- Now all that is left is to install Guix with a @code{guix system init}
- and restart.
- However we first need to set up a chroot, because the root partition of
- the rescue system is mounted on an aufs partition and if you try to
- install Guix it will fail at the GRUB install step complaining about the
- canonical path of "aufs".
- Install packages that will be used in the chroot:
- @example
- guix install bash-static parted util-linux-with-udev coreutils guix
- @end example
- Then run the following to create directories needed for the chroot:
- @example
- cd /mnt && \
- mkdir -p bin etc gnu/store root/.guix-profile/ root/.config/guix/current \
- var/guix proc sys dev
- @end example
- Copy the host resolv.conf in the chroot:
- @example
- cp /etc/resolv.conf etc/
- @end example
- Mount block devices, the store and its database and the current guix config:
- @example
- mount --rbind /proc /mnt/proc
- mount --rbind /sys /mnt/sys
- mount --rbind /dev /mnt/dev
- mount --rbind /var/guix/ var/guix/
- mount --rbind /gnu/store gnu/store/
- mount --rbind /root/.config/ root/.config/
- mount --rbind /root/.guix-profile/bin/ bin
- mount --rbind /root/.guix-profile root/.guix-profile/
- @end example
- Chroot in /mnt and install the system:
- @example
- chroot /mnt/ /bin/bash
- guix system init /root/os.scm /guix
- @end example
- Finally, from the web user interface (UI), change @samp{netboot} to
- @samp{boot to disk} and restart (also from the web UI).
- Wait a few minutes and try to ssh with @code{ssh
- guix@@@var{server-ip-address>} -i @var{path-to-your-ssh-key}}
- You should have a Guix system up and running on Kimsufi;
- congratulations!
- @node Setting up a bind mount
- @section Setting up a bind mount
- To bind mount a file system, one must first set up some definitions
- before the @code{operating-system} section of the system definition. In
- this example we will bind mount a folder from a spinning disk drive to
- @file{/tmp}, to save wear and tear on the primary SSD, without
- dedicating an entire partition to be mounted as @file{/tmp}.
- First, the source drive that hosts the folder we wish to bind mount
- should be defined, so that the bind mount can depend on it.
- @lisp
- (define source-drive ;; "source-drive" can be named anything you want.
- (file-system
- (device (uuid "UUID goes here"))
- (mount-point "/path-to-spinning-disk-goes-here")
- (type "ext4"))) ;; Make sure to set this to the appropriate type for your drive.
- @end lisp
- The source folder must also be defined, so that guix will know it's not
- a regular block device, but a folder.
- @lisp
- (define (%source-directory) "/path-to-spinning-disk-goes-here/tmp") ;; "source-directory" can be named any valid variable name.
- @end lisp
- Finally, inside the @code{file-systems} definition, we must add the
- mount itself.
- @lisp
- (file-systems (cons*
- ...<other drives omitted for clarity>...
- source-drive ;; Must match the name you gave the source drive in the earlier definition.
- (file-system
- (device (%source-directory)) ;; Make sure "source-directory" matches your earlier definition.
- (mount-point "/tmp")
- (type "none") ;; We are mounting a folder, not a partition, so this type needs to be "none"
- (flags '(bind-mount))
- (dependencies (list source-drive)) ;; Ensure "source-drive" matches what you've named the variable for the drive.
- )
- ...<other drives omitted for clarity>...
- ))
- @end lisp
- @node Getting substitutes from Tor
- @section Getting substitutes from Tor
- Guix daemon can use a HTTP proxy to get substitutes, here we are
- configuring it to get them via Tor.
- @quotation Warning
- @emph{Not all} Guix daemon's traffic will go through Tor! Only
- HTTP/HTTPS will get proxied; FTP, Git protocol, SSH, etc connections
- will still go through the clearnet. Again, this configuration isn't
- foolproof some of your traffic won't get routed by Tor at all. Use it
- at your own risk.
- Also note that the procedure described here applies only to package
- substitution. When you update your guix distribution with
- @command{guix pull}, you still need to use @command{torsocks} if
- you want to route the connection to guix's git repository servers
- through Tor.
- @end quotation
- Guix's substitute server is available as a Onion service, if you want
- to use it to get your substitutes through Tor configure your system as
- follow:
- @lisp
- (use-modules (gnu))
- (use-service-module base networking)
- (operating-system
- …
- (services
- (cons
- (service tor-service-type
- (tor-configuration
- (config-file (plain-file "tor-config"
- "HTTPTunnelPort 127.0.0.1:9250"))))
- (modify-services %base-services
- (guix-service-type
- config => (guix-configuration
- (inherit config)
- ;; ci.guix.gnu.org's Onion service
- (substitute-urls
- "@value{SUBSTITUTE-TOR-URL}")
- (http-proxy "http://localhost:9250")))))))
- @end lisp
- This will keep a tor process running that provides a HTTP CONNECT tunnel
- which will be used by @command{guix-daemon}. The daemon can use other
- protocols than HTTP(S) to get remote resources, request using those
- protocols won't go through Tor since we are only setting a HTTP tunnel
- here. Note that @code{substitutes-urls} is using HTTPS and not HTTP or
- it won't work, that's a limitation of Tor's tunnel; you may want to use
- @command{privoxy} instead to avoid such limitations.
- If you don't want to always get substitutes through Tor but using it just
- some of the times, then skip the @code{guix-configuration}. When you
- want to get a substitute from the Tor tunnel run:
- @example
- sudo herd set-http-proxy guix-daemon http://localhost:9250
- guix build \
- --substitute-urls=@value{SUBSTITUTE-TOR-URL} @dots{}
- @end example
- @node Setting up NGINX with Lua
- @section Setting up NGINX with Lua
- @cindex nginx, lua, openresty, resty
- NGINX could be extended with Lua scripts.
- Guix provides NGINX service with ability to load Lua module and specific
- Lua packages, and reply to requests by evaluating Lua scripts.
- The following example demonstrates system definition with configuration
- to evaluate @file{index.lua} Lua script on HTTP request to
- @uref{http://localhost/hello} endpoint:
- @example
- local shell = require "resty.shell"
- local stdin = ""
- local timeout = 1000 -- ms
- local max_size = 4096 -- byte
- local ok, stdout, stderr, reason, status =
- shell.run([[/run/current-system/profile/bin/ls /tmp]], stdin, timeout, max_size)
- ngx.say(stdout)
- @end example
- @lisp
- (use-modules (gnu))
- (use-service-modules #;… web)
- (use-package-modules #;… lua)
- (operating-system
- ;; …
- (services
- ;; …
- (service nginx-service-type
- (nginx-configuration
- (modules
- (list
- (file-append nginx-lua-module "/etc/nginx/modules/ngx_http_lua_module.so")))
- (lua-package-path (list lua-resty-core
- lua-resty-lrucache
- lua-resty-signal
- lua-tablepool
- lua-resty-shell))
- (lua-package-cpath (list lua-resty-signal))
- (server-blocks
- (list (nginx-server-configuration
- (server-name '("localhost"))
- (listen '("80"))
- (root "/etc")
- (locations (list
- (nginx-location-configuration
- (uri "/hello")
- (body (list #~(format #f "content_by_lua_file ~s;"
- #$(local-file "index.lua"))))))))))))))
- @end lisp
- @node Music Server with Bluetooth Audio
- @section Music Server with Bluetooth Audio
- @cindex mpd
- @cindex music server, headless
- @cindex bluetooth, ALSA configuration
- MPD, the Music Player Daemon, is a flexible server-side application for
- playing music. Client programs on different machines on the network ---
- a mobile phone, a laptop, a desktop workstation --- can connect to it to
- control the playback of audio files from your local music collection.
- MPD decodes the audio files and plays them back on one or many outputs.
- By default MPD will play to the default audio device. In the example
- below we make things a little more interesting by setting up a headless
- music server. There will be no graphical user interface, no Pulseaudio
- daemon, and no local audio output. Instead we will configure MPD with
- two outputs: a bluetooth speaker and a web server to serve audio streams
- to any streaming media player.
- Bluetooth is often rather frustrating to set up. You will have to pair
- your Bluetooth device and make sure that the device is automatically
- connected as soon as it powers on. The Bluetooth system service
- returned by the @code{bluetooth-service} procedure provides the
- infrastructure needed to set this up.
- Reconfigure your system with at least the following services and
- packages:
- @lisp
- (operating-system
- ;; …
- (packages (cons* bluez bluez-alsa
- %base-packages))
- (services
- ;; …
- (dbus-service #:services (list bluez-alsa))
- (bluetooth-service #:auto-enable? #t)))
- @end lisp
- Start the @code{bluetooth} service and then use @command{bluetoothctl}
- to scan for Bluetooth devices. Try to identify your Bluetooth speaker
- and pick out its device ID from the resulting list of devices that is
- indubitably dominated by a baffling smorgasbord of your neighbors' home
- automation gizmos. This only needs to be done once:
- @example
- $ bluetoothctl
- [NEW] Controller 00:11:22:33:95:7F BlueZ 5.40 [default]
- [bluetooth]# power on
- [bluetooth]# Changing power on succeeded
- [bluetooth]# agent on
- [bluetooth]# Agent registered
- [bluetooth]# default-agent
- [bluetooth]# Default agent request successful
- [bluetooth]# scan on
- [bluetooth]# Discovery started
- [CHG] Controller 00:11:22:33:95:7F Discovering: yes
- [NEW] Device AA:BB:CC:A4:AA:CD My Bluetooth Speaker
- [NEW] Device 44:44:FF:2A:20:DC My Neighbor's TV
- @dots{}
- [bluetooth]# pair AA:BB:CC:A4:AA:CD
- Attempting to pair with AA:BB:CC:A4:AA:CD
- [CHG] Device AA:BB:CC:A4:AA:CD Connected: yes
- [My Bluetooth Speaker]# [CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110b-0000-1000-8000-00xxxxxxxxxx
- [CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110c-0000-1000-8000-00xxxxxxxxxx
- [CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110e-0000-1000-8000-00xxxxxxxxxx
- [CHG] Device AA:BB:CC:A4:AA:CD Paired: yes
- Pairing successful
- [CHG] Device AA:BB:CC:A4:AA:CD Connected: no
- [bluetooth]#
- [bluetooth]# trust AA:BB:CC:A4:AA:CD
- [bluetooth]# [CHG] Device AA:BB:CC:A4:AA:CD Trusted: yes
- Changing AA:BB:CC:A4:AA:CD trust succeeded
- [bluetooth]#
- [bluetooth]# connect AA:BB:CC:A4:AA:CD
- Attempting to connect to AA:BB:CC:A4:AA:CD
- [bluetooth]# [CHG] Device AA:BB:CC:A4:AA:CD RSSI: -63
- [CHG] Device AA:BB:CC:A4:AA:CD Connected: yes
- Connection successful
- [My Bluetooth Speaker]# scan off
- [CHG] Device AA:BB:CC:A4:AA:CD RSSI is nil
- Discovery stopped
- [CHG] Controller 00:11:22:33:95:7F Discovering: no
- @end example
- Congratulations, you can now automatically connect to your Bluetooth
- speaker!
- It is now time to configure ALSA to use the @emph{bluealsa} Bluetooth
- module, so that you can define an ALSA pcm device corresponding to your
- Bluetooth speaker. For a headless server using @emph{bluealsa} with a
- fixed Bluetooth device is likely simpler than configuring Pulseaudio and
- its stream switching behavior. We configure ALSA by crafting a custom
- @code{alsa-configuration} for the @code{alsa-service-type}. The
- configuration will declare a @code{pcm} type @code{bluealsa} from the
- @code{bluealsa} module provided by the @code{bluez-alsa} package, and
- then define a @code{pcm} device of that type for your Bluetooth speaker.
- All that is left then is to make MPD send audio data to this ALSA
- device. We also add a secondary MPD output that makes the currently
- played audio files available as a stream through a web server on port
- 8080. When enabled a device on the network could listen to the audio
- stream by connecting any capable media player to the HTTP server on port
- 8080, independent of the status of the Bluetooth speaker.
- What follows is the outline of an @code{operating-system} declaration
- that should accomplish the above-mentioned tasks:
- @lisp
- (use-modules (gnu))
- (use-service-modules audio dbus sound #;… etc)
- (use-package-modules audio linux #;… etc)
- (operating-system
- ;; …
- (packages (cons* bluez bluez-alsa
- %base-packages))
- (services
- ;; …
- (service mpd-service-type
- (mpd-configuration
- (user "your-username")
- (music-dir "/path/to/your/music")
- (address "192.168.178.20")
- (outputs (list (mpd-output
- (type "alsa")
- (name "MPD")
- (extra-options
- ;; Use the same name as in the ALSA
- ;; configuration below.
- '((device . "pcm.btspeaker"))))
- (mpd-output
- (type "httpd")
- (name "streaming")
- (enabled? #false)
- (always-on? #true)
- (tags? #true)
- (mixer-type 'null)
- (extra-options
- '((encoder . "vorbis")
- (port . "8080")
- (bind-to-address . "192.168.178.20")
- (max-clients . "0") ;no limit
- (quality . "5.0")
- (format . "44100:16:1"))))))))
- (dbus-service #:services (list bluez-alsa))
- (bluetooth-service #:auto-enable? #t)
- (service alsa-service-type
- (alsa-configuration
- (pulseaudio? #false) ;we don't need it
- (extra-options
- #~(string-append "\
- # Declare Bluetooth audio device type \"bluealsa\" from bluealsa module
- pcm_type.bluealsa @{
- lib \"" #$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_pcm_bluealsa.so") "\"
- @}
- # Declare control device type \"bluealsa\" from the same module
- ctl_type.bluealsa @{
- lib \"" #$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_ctl_bluealsa.so") "\"
- @}
- # Define the actual Bluetooth audio device.
- pcm.btspeaker @{
- type bluealsa
- device \"AA:BB:CC:A4:AA:CD\" # unique device identifier
- profile \"a2dp\"
- @}
- # Define an associated controller.
- ctl.btspeaker @{
- type bluealsa
- @}
- "))))))
- @end lisp
- Enjoy the music with the MPD client of your choice or a media player
- capable of streaming via HTTP!
- @c *********************************************************************
- @node Containers
- @chapter Containers
- The kernel Linux provides a number of shared facilities that are
- available to processes in the system. These facilities include a shared
- view on the file system, other processes, network devices, user and
- group identities, and a few others. Since Linux 3.19 a user can choose
- to @emph{unshare} some of these shared facilities for selected
- processes, providing them (and their child processes) with a different
- view on the system.
- A process with an unshared @code{mount} namespace, for example, has its
- own view on the file system --- it will only be able to see directories
- that have been explicitly bound in its mount namespace. A process with
- its own @code{proc} namespace will consider itself to be the only
- process running on the system, running as PID 1.
- Guix uses these kernel features to provide fully isolated environments
- and even complete Guix System containers, lightweight virtual machines
- that share the host system's kernel. This feature comes in especially
- handy when using Guix on a foreign distribution to prevent interference
- from foreign libraries or configuration files that are available
- system-wide.
- @menu
- * Guix Containers:: Perfectly isolated environments
- * Guix System Containers:: A system inside your system
- @end menu
- @node Guix Containers
- @section Guix Containers
- The easiest way to get started is to use @command{guix shell} with the
- @option{--container} option. @xref{Invoking guix shell,,, guix, GNU
- Guix Reference Manual} for a reference of valid options.
- The following snippet spawns a minimal shell process with most
- namespaces unshared from the system. The current working directory is
- visible to the process, but anything else on the file system is
- unavailable. This extreme isolation can be very useful when you want to
- rule out any sort of interference from environment variables, globally
- installed libraries, or configuration files.
- @example
- guix shell --container
- @end example
- It is a bleak environment, barren, desolate. You will find that not
- even the GNU coreutils are available here, so to explore this deserted
- wasteland you need to use built-in shell commands. Even the usually
- gigantic @file{/gnu/store} directory is reduced to a faint shadow of
- itself.
- @example sh
- $ echo /gnu/store/*
- /gnu/store/@dots{}-gcc-10.3.0-lib
- /gnu/store/@dots{}-glibc-2.33
- /gnu/store/@dots{}-bash-static-5.1.8
- /gnu/store/@dots{}-ncurses-6.2.20210619
- /gnu/store/@dots{}-bash-5.1.8
- /gnu/store/@dots{}-profile
- /gnu/store/@dots{}-readline-8.1.1
- @end example
- @cindex exiting a container
- There isn't much you can do in an environment like this other than
- exiting it. You can use @key{^D} or @command{exit} to terminate this
- limited shell environment.
- @cindex exposing directories, container
- @cindex sharing directories, container
- @cindex mapping locations, container
- You can make other directories available inside of the container
- environment; use @option{--expose=DIRECTORY} to bind-mount the given
- directory as a read-only location inside the container, or use
- @option{--share=DIRECTORY} to make the location writable. With an
- additional mapping argument after the directory name you can control the
- name of the directory inside the container. In the following example we
- map @file{/etc} on the host system to @file{/the/host/etc} inside a
- container in which the GNU coreutils are installed.
- @example sh
- $ guix shell --container --share=/etc=/the/host/etc coreutils
- $ ls /the/host/etc
- @end example
- Similarly, you can prevent the current working directory from being
- mapped into the container with the @option{--no-cwd} option. Another
- good idea is to create a dedicated directory that will serve as the
- container's home directory, and spawn the container shell from that
- directory.
- @cindex hide system libraries, container
- @cindex avoid ABI mismatch, container
- On a foreign system a container environment can be used to compile
- software that cannot possibly be linked with system libraries or with
- the system's compiler toolchain. A common use-case in a research
- context is to install packages from within an R session. Outside of a
- container environment there is a good chance that the foreign compiler
- toolchain and incompatible system libraries are found first, resulting
- in incompatible binaries that cannot be used by R. In a container shell
- this problem disappears, as system libraries and executables simply
- aren't available due to the unshared @code{mount} namespace.
- Let's take a comprehensive manifest providing a comfortable development
- environment for use with R:
- @lisp
- (specifications->manifest
- (list "r-minimal"
- ;; base packages
- "bash-minimal"
- "glibc-locales"
- "nss-certs"
- ;; Common command line tools lest the container is too empty.
- "coreutils"
- "grep"
- "which"
- "wget"
- "sed"
- ;; R markdown tools
- "pandoc"
- ;; Toolchain and common libraries for "install.packages"
- "gcc-toolchain@@10"
- "gfortran-toolchain"
- "gawk"
- "tar"
- "gzip"
- "unzip"
- "make"
- "cmake"
- "pkg-config"
- "cairo"
- "libxt"
- "openssl"
- "curl"
- "zlib"))
- @end lisp
- Let's use this to run R inside a container environment. For convenience
- we share the @code{net} namespace to use the host system's network
- interfaces. Now we can build R packages from source the traditional way
- without having to worry about ABI mismatch or incompatibilities.
- @example sh
- $ guix shell --container --network --manifest=manifest.scm -- R
- R version 4.2.1 (2022-06-23) -- "Funny-Looking Kid"
- Copyright (C) 2022 The R Foundation for Statistical Computing
- @dots{}
- > e <- Sys.getenv("GUIX_ENVIRONMENT")
- > Sys.setenv(GIT_SSL_CAINFO=paste0(e, "/etc/ssl/certs/ca-certificates.crt"))
- > Sys.setenv(SSL_CERT_FILE=paste0(e, "/etc/ssl/certs/ca-certificates.crt"))
- > Sys.setenv(SSL_CERT_DIR=paste0(e, "/etc/ssl/certs"))
- > install.packages("Cairo", lib=paste0(getwd()))
- @dots{}
- * installing *source* package 'Cairo' ...
- @dots{}
- * DONE (Cairo)
- The downloaded source packages are in
- '/tmp/RtmpCuwdwM/downloaded_packages'
- > library("Cairo", lib=getwd())
- > # success!
- @end example
- Using container shells is fun, but they can become a little cumbersome
- when you want to go beyond just a single interactive process. Some
- tasks become a lot easier when they sit on the rock solid foundation of
- a proper Guix System and its rich set of system services. The next
- section shows you how to launch a complete Guix System inside of a
- container.
- @node Guix System Containers
- @section Guix System Containers
- The Guix System provides a wide array of interconnected system services
- that are configured declaratively to form a dependable stateless GNU
- System foundation for whatever tasks you throw at it. Even when using
- Guix on a foreign distribution you can benefit from the design of Guix
- System by running a system instance as a container. Using the same
- kernel features of unshared namespaces mentioned in the previous
- section, the resulting Guix System instance is isolated from the host
- system and only shares file system locations that you explicitly
- declare.
- A Guix System container differs from the shell process created by
- @command{guix shell --container} in a number of important ways. While
- in a container shell the containerized process is a Bash shell process,
- a Guix System container runs the Shepherd as PID 1. In a system
- container all system services (@pxref{Services,,, guix, GNU Guix
- Reference Manual}) are set up just as they would be on a Guix System in
- a virtual machine or on bare metal---this includes daemons managed by
- the GNU@tie{}Shepherd (@pxref{Shepherd Services,,, guix, GNU Guix
- Reference Manual}) as well as other kinds of extensions to the operating
- system (@pxref{Service Composition,,, guix, GNU Guix Reference Manual}).
- The perceived increase in complexity of running a Guix System container
- is easily justified when dealing with more complex applications that
- have higher or just more rigid requirements on their execution
- contexts---configuration files, dedicated user accounts, directories for
- caches or log files, etc. In Guix System the demands of this kind of
- software are satisfied through the deployment of system services.
- @menu
- * A Database Container::
- * Container Networking::
- @end menu
- @node A Database Container
- @subsection A Database Container
- A good example might be a PostgreSQL database server. Much of the
- complexity of setting up such a database server is encapsulated in this
- deceptively short service declaration:
- @lisp
- (service postgresql-service-type
- (postgresql-configuration
- (postgresql postgresql-14)))
- @end lisp
- A complete operating system declaration for use with a Guix System
- container would look something like this:
- @lisp
- (use-modules (gnu))
- (use-package-modules databases)
- (use-service-modules databases)
- (operating-system
- (host-name "container")
- (timezone "Europe/Berlin")
- (file-systems (cons (file-system
- (device (file-system-label "does-not-matter"))
- (mount-point "/")
- (type "ext4"))
- %base-file-systems))
- (bootloader (bootloader-configuration
- (bootloader grub-bootloader)
- (targets '("/dev/sdX"))))
- (services
- (cons* (service postgresql-service-type
- (postgresql-configuration
- (postgresql postgresql-14)
- (config-file
- (postgresql-config-file
- (log-destination "stderr")
- (hba-file
- (plain-file "pg_hba.conf"
- "\
- local all all trust
- host all all 10.0.0.1/32 trust"))
- (extra-config
- '(("listen_addresses" "*")
- ("log_directory" "/var/log/postgresql")))))))
- (service postgresql-role-service-type
- (postgresql-role-configuration
- (roles
- (list (postgresql-role
- (name "test")
- (create-database? #t))))))
- %base-services)))
- @end lisp
- With @code{postgresql-role-service-type} we define a role ``test'' and
- create a matching database, so that we can test right away without any
- further manual setup. The @code{postgresql-config-file} settings allow
- a client from IP address 10.0.0.1 to connect without requiring
- authentication---a bad idea in production systems, but convenient for
- this example.
- Let's build a script that will launch an instance of this Guix System as
- a container. Write the @code{operating-system} declaration above to a
- file @file{os.scm} and then use @command{guix system container} to build
- the launcher. (@pxref{Invoking guix system,,, guix, GNU Guix Reference
- Manual}).
- @example
- $ guix system container os.scm
- The following derivations will be built:
- /gnu/store/@dots{}-run-container.drv
- @dots{}
- building /gnu/store/@dots{}-run-container.drv...
- /gnu/store/@dots{}-run-container
- @end example
- Now that we have a launcher script we can run it to spawn the new system
- with a running PostgreSQL service. Note that due to some as yet
- unresolved limitations we need to run the launcher as the root user, for
- example with @command{sudo}.
- @example
- $ sudo /gnu/store/@dots{}-run-container
- system container is running as PID 5983
- @dots{}
- @end example
- Background the process with @key{Ctrl-z} followed by @command{bg}. Note
- the process ID in the output; we will need it to connect to the
- container later. You know what? Let's try attaching to the container
- right now. We will use @command{nsenter}, a tool provided by the
- @code{util-linux} package:
- @example
- $ guix shell util-linux
- $ sudo nsenter -a -t 5983
- root@@container /# pgrep -a postgres
- 49 /gnu/store/@dots{}-postgresql-14.4/bin/postgres -D /var/lib/postgresql/data --config-file=/gnu/store/@dots{}-postgresql.conf -p 5432
- 51 postgres: checkpointer
- 52 postgres: background writer
- 53 postgres: walwriter
- 54 postgres: autovacuum launcher
- 55 postgres: stats collector
- 56 postgres: logical replication launcher
- root@@container /# exit
- @end example
- The PostgreSQL service is running in the container!
- @node Container Networking
- @subsection Container Networking
- @cindex container networking
- What good is a Guix System running a PostgreSQL database service as a
- container when we can only talk to it with processes originating in the
- container? It would be much better if we could talk to the database
- over the network.
- The easiest way to do this is to create a pair of connected virtual
- Ethernet devices (known as @code{veth}). We move one of the devices
- (@code{ceth-test}) into the @code{net} namespace of the container and
- leave the other end (@code{veth-test}) of the connection on the host
- system.
- @example
- pid=5983
- ns="guix-test"
- host="veth-test"
- client="ceth-test"
- # Attach the new net namespace "guix-test" to the container PID.
- sudo ip netns attach $ns $pid
- # Create the pair of devices
- sudo ip link add $host type veth peer name $client
- # Move the client device into the container's net namespace
- sudo ip link set $client netns $ns
- @end example
- Then we configure the host side:
- @example
- sudo ip link set $host up
- sudo ip addr add 10.0.0.1/24 dev $host
- @end example
- @dots{}and then we configure the client side:
- @example
- sudo ip netns exec $ns ip link set lo up
- sudo ip netns exec $ns ip link set $client up
- sudo ip netns exec $ns ip addr add 10.0.0.2/24 dev $client
- @end example
- At this point the host can reach the container at IP address 10.0.0.2,
- and the container can reach the host at IP 10.0.0.1. This is all we
- need to talk to the database server inside the container from the host
- system on the outside.
- @example
- $ psql -h 10.0.0.2 -U test
- psql (14.4)
- Type "help" for help.
- test=> CREATE TABLE hello (who TEXT NOT NULL);
- CREATE TABLE
- test=> INSERT INTO hello (who) VALUES ('world');
- INSERT 0 1
- test=> SELECT * FROM hello;
- who
- -------
- world
- (1 row)
- @end example
- Now that we're done with this little demonstration let's clean up:
- @example
- sudo kill $pid
- sudo ip netns del $ns
- sudo ip link del $host
- @end example
- @c *********************************************************************
- @node Advanced package management
- @chapter Advanced package management
- Guix is a functional package manager that offers many features beyond
- what more traditional package managers can do. To the uninitiated,
- those features might not have obvious use cases at first. The purpose
- of this chapter is to demonstrate some advanced package management
- concepts.
- @pxref{Package Management,,, guix, GNU Guix Reference Manual} for a complete
- reference.
- @menu
- * Guix Profiles in Practice:: Strategies for multiple profiles and manifests.
- @end menu
- @node Guix Profiles in Practice
- @section Guix Profiles in Practice
- Guix provides a very useful feature that may be quite foreign to newcomers:
- @emph{profiles}. They are a way to group package installations together and all users
- on the same system are free to use as many profiles as they want.
- Whether you're a developer or not, you may find that multiple profiles bring you
- great power and flexibility. While they shift the paradigm somewhat compared to
- @emph{traditional package managers}, they are very convenient to use once you've
- understood how to set them up.
- If you are familiar with Python's @samp{virtualenv}, you can think of a profile as a
- kind of universal @samp{virtualenv} that can hold any kind of software whatsoever, not
- just Python software. Furthermore, profiles are self-sufficient: they capture
- all the runtime dependencies which guarantees that all programs within a profile
- will always work at any point in time.
- Multiple profiles have many benefits:
- @itemize
- @item
- Clean semantic separation of the various packages a user needs for different contexts.
- @item
- Multiple profiles can be made available into the environment either on login
- or within a dedicated shell.
- @item
- Profiles can be loaded on demand. For instance, the user can use multiple
- shells, each of them running different profiles.
- @item
- Isolation: Programs from one profile will not use programs from the other, and
- the user can even install different versions of the same programs to the two
- profiles without conflict.
- @item
- Deduplication: Profiles share dependencies that happens to be the exact same.
- This makes multiple profiles storage-efficient.
- @item
- Reproducible: when used with declarative manifests, a profile can be fully
- specified by the Guix commit that was active when it was set up. This means
- that the exact same profile can be
- @uref{https://guix.gnu.org/blog/2018/multi-dimensional-transactions-and-rollbacks-oh-my/,
- set up anywhere and anytime}, with just the commit information. See the
- section on @ref{Reproducible profiles}.
- @item
- Easier upgrades and maintenance: Multiple profiles make it easy to keep
- package listings at hand and make upgrades completely frictionless.
- @end itemize
- Concretely, here follows some typical profiles:
- @itemize
- @item
- The dependencies of a project you are working on.
- @item
- Your favourite programming language libraries.
- @item
- Laptop-specific programs (like @samp{powertop}) that you don't need on a desktop.
- @item
- @TeX{}live (this one can be really useful when you need to install just one
- package for this one document you've just received over email).
- @item
- Games.
- @end itemize
- Let's dive in the set up!
- @menu
- * Basic setup with manifests::
- * Required packages::
- * Default profile::
- * The benefits of manifests::
- * Reproducible profiles::
- @end menu
- @node Basic setup with manifests
- @subsection Basic setup with manifests
- A Guix profile can be set up @i{via} a @dfn{manifest}. A manifest is a
- snippet of Scheme code that specifies the set of packages you want to
- have in your profile; it looks like this:
- @lisp
- (specifications->manifest
- '("package-1"
- ;; Version 1.3 of package-2.
- "package-2@@1.3"
- ;; The "lib" output of package-3.
- "package-3:lib"
- ; ...
- "package-N"))
- @end lisp
- @xref{Writing Manifests,,, guix, GNU Guix Reference Manual}, for
- more information about the syntax.
- We can create a manifest specification per profile and install them this way:
- @example
- GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
- mkdir -p "$GUIX_EXTRA_PROFILES"/my-project # if it does not exist yet
- guix package --manifest=/path/to/guix-my-project-manifest.scm --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project
- @end example
- Here we set an arbitrary variable @samp{GUIX_EXTRA_PROFILES} to point to the directory
- where we will store our profiles in the rest of this article.
- Placing all your profiles in a single directory, with each profile getting its
- own sub-directory, is somewhat cleaner. This way, each sub-directory will
- contain all the symlinks for precisely one profile. Besides, ``looping over
- profiles'' becomes obvious from any programming language (e.g.@: a shell script) by
- simply looping over the sub-directories of @samp{$GUIX_EXTRA_PROFILES}.
- Note that it's also possible to loop over the output of
- @example
- guix package --list-profiles
- @end example
- although you'll probably have to filter out @file{~/.config/guix/current}.
- To enable all profiles on login, add this to your @file{~/.bash_profile} (or similar):
- @example
- for i in $GUIX_EXTRA_PROFILES/*; do
- profile=$i/$(basename "$i")
- if [ -f "$profile"/etc/profile ]; then
- GUIX_PROFILE="$profile"
- . "$GUIX_PROFILE"/etc/profile
- fi
- unset profile
- done
- @end example
- Note to Guix System users: the above reflects how your default profile
- @file{~/.guix-profile} is activated from @file{/etc/profile}, that latter being loaded by
- @file{~/.bashrc} by default.
- You can obviously choose to only enable a subset of them:
- @example
- for i in "$GUIX_EXTRA_PROFILES"/my-project-1 "$GUIX_EXTRA_PROFILES"/my-project-2; do
- profile=$i/$(basename "$i")
- if [ -f "$profile"/etc/profile ]; then
- GUIX_PROFILE="$profile"
- . "$GUIX_PROFILE"/etc/profile
- fi
- unset profile
- done
- @end example
- When a profile is off, it's straightforward to enable it for an individual shell
- without "polluting" the rest of the user session:
- @example
- GUIX_PROFILE="path/to/my-project" ; . "$GUIX_PROFILE"/etc/profile
- @end example
- The key to enabling a profile is to @emph{source} its @samp{etc/profile} file. This file
- contains shell code that exports the right environment variables necessary to
- activate the software contained in the profile. It is built automatically by
- Guix and meant to be sourced.
- It contains the same variables you would get if you ran:
- @example
- guix package --search-paths=prefix --profile=$my_profile"
- @end example
- Once again, see (@pxref{Invoking guix package,,, guix, GNU Guix Reference Manual})
- for the command line options.
- To upgrade a profile, simply install the manifest again:
- @example
- guix package -m /path/to/guix-my-project-manifest.scm -p "$GUIX_EXTRA_PROFILES"/my-project/my-project
- @end example
- To upgrade all profiles, it's easy enough to loop over them. For instance,
- assuming your manifest specifications are stored in
- @file{~/.guix-manifests/guix-$profile-manifest.scm}, with @samp{$profile} being the name
- of the profile (e.g.@: "project1"), you could do the following in Bourne shell:
- @example
- for profile in "$GUIX_EXTRA_PROFILES"/*; do
- guix package --profile="$profile" --manifest="$HOME/.guix-manifests/guix-$profile-manifest.scm"
- done
- @end example
- Each profile has its own generations:
- @example
- guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --list-generations
- @end example
- You can roll-back to any generation of a given profile:
- @example
- guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --switch-generations=17
- @end example
- Finally, if you want to switch to a profile without inheriting from the
- current environment, you can activate it from an empty shell:
- @example
- env -i $(which bash) --login --noprofile --norc
- . my-project/etc/profile
- @end example
- @node Required packages
- @subsection Required packages
- Activating a profile essentially boils down to exporting a bunch of
- environmental variables. This is the role of the @samp{etc/profile} within the
- profile.
- @emph{Note: Only the environmental variables of the packages that consume them will
- be set.}
- For instance, @samp{MANPATH} won't be set if there is no consumer application for man
- pages within the profile. So if you need to transparently access man pages once
- the profile is loaded, you've got two options:
- @itemize
- @item
- Either export the variable manually, e.g.
- @example
- export MANPATH=/path/to/profile$@{MANPATH:+:@}$MANPATH
- @end example
- @item
- Or include @samp{man-db} to the profile manifest.
- @end itemize
- The same is true for @samp{INFOPATH} (you can install @samp{info-reader}),
- @samp{PKG_CONFIG_PATH} (install @samp{pkg-config}), etc.
- @node Default profile
- @subsection Default profile
- What about the default profile that Guix keeps in @file{~/.guix-profile}?
- You can assign it the role you want. Typically you would install the manifest
- of the packages you want to use all the time.
- Alternatively, you could keep it ``manifest-less'' for throw-away packages
- that you would just use for a couple of days.
- This way makes it convenient to run
- @example
- guix install package-foo
- guix upgrade package-bar
- @end example
- without having to specify the path to a profile.
- @node The benefits of manifests
- @subsection The benefits of manifests
- Manifests are a convenient way to keep your package lists around and, say,
- to synchronize them across multiple machines using a version control system.
- A common complaint about manifests is that they can be slow to install when they
- contain large number of packages. This is especially cumbersome when you just
- want get an upgrade for one package within a big manifest.
- This is one more reason to use multiple profiles, which happen to be just
- perfect to break down manifests into multiple sets of semantically connected
- packages. Using multiple, small profiles provides more flexibility and
- usability.
- Manifests come with multiple benefits. In particular, they ease maintenance:
- @itemize
- @item
- When a profile is set up from a manifest, the manifest itself is
- self-sufficient to keep a ``package listing'' around and reinstall the profile
- later or on a different system. For ad-hoc profiles, we would need to
- generate a manifest specification manually and maintain the package versions
- for the packages that don't use the default version.
- @item
- @code{guix package --upgrade} always tries to update the packages that have
- propagated inputs, even if there is nothing to do. Guix manifests remove this
- problem.
- @item
- When partially upgrading a profile, conflicts may arise (due to diverging
- dependencies between the updated and the non-updated packages) and they can be
- annoying to resolve manually. Manifests remove this problem altogether since
- all packages are always upgraded at once.
- @item
- As mentioned above, manifests allow for reproducible profiles, while the
- imperative @code{guix install}, @code{guix upgrade}, etc. do not, since they produce
- different profiles every time even when they hold the same packages. See
- @uref{https://issues.guix.gnu.org/issue/33285, the related discussion on the matter}.
- @item
- Manifest specifications are usable by other @samp{guix} commands. For example, you
- can run @code{guix weather -m manifest.scm} to see how many substitutes are
- available, which can help you decide whether you want to try upgrading today
- or wait a while. Another example: you can run @code{guix pack -m manifest.scm} to
- create a pack containing all the packages in the manifest (and their
- transitive references).
- @item
- Finally, manifests have a Scheme representation, the @samp{<manifest>} record type.
- They can be manipulated in Scheme and passed to the various Guix @uref{https://en.wikipedia.org/wiki/Api, APIs}.
- @end itemize
- It's important to understand that while manifests can be used to declare
- profiles, they are not strictly equivalent: profiles have the side effect that
- they ``pin'' packages in the store, which prevents them from being
- garbage-collected (@pxref{Invoking guix gc,,, guix, GNU Guix Reference Manual})
- and ensures that they will still be available at any point in
- the future.
- Let's take an example:
- @enumerate
- @item
- We have an environment for hacking on a project for which there isn't a Guix
- package yet. We build the environment using a manifest, and then run @code{guix
- environment -m manifest.scm}. So far so good.
- @item
- Many weeks pass and we have run a couple of @code{guix pull} in the mean time.
- Maybe a dependency from our manifest has been updated; or we may have run
- @code{guix gc} and some packages needed by our manifest have been
- garbage-collected.
- @item
- Eventually, we set to work on that project again, so we run @code{guix shell
- -m manifest.scm}. But now we have to wait for Guix to build and install
- stuff!
- @end enumerate
- Ideally, we could spare the rebuild time. And indeed we can, all we need is to
- install the manifest to a profile and use @code{GUIX_PROFILE=/the/profile;
- . "$GUIX_PROFILE"/etc/profile} as explained above: this guarantees that our
- hacking environment will be available at all times.
- @emph{Security warning:} While keeping old profiles around can be convenient, keep in
- mind that outdated packages may not have received the latest security fixes.
- @node Reproducible profiles
- @subsection Reproducible profiles
- To reproduce a profile bit-for-bit, we need two pieces of information:
- @itemize
- @item
- a manifest,
- @item
- a Guix channel specification.
- @end itemize
- Indeed, manifests alone might not be enough: different Guix versions (or
- different channels) can produce different outputs for a given manifest.
- You can output the Guix channel specification with @samp{guix describe
- --format=channels}.
- Save this to a file, say @samp{channel-specs.scm}.
- On another computer, you can use the channel specification file and the manifest
- to reproduce the exact same profile:
- @example
- GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
- GUIX_EXTRA=$HOME/.guix-extra
- mkdir -p "$GUIX_EXTRA"/my-project
- guix pull --channels=channel-specs.scm --profile="$GUIX_EXTRA/my-project/guix"
- mkdir -p "$GUIX_EXTRA_PROFILES/my-project"
- "$GUIX_EXTRA"/my-project/guix/bin/guix package --manifest=/path/to/guix-my-project-manifest.scm --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project
- @end example
- It's safe to delete the Guix channel profile you've just installed with the
- channel specification, the project profile does not depend on it.
- @c *********************************************************************
- @node Environment management
- @chapter Environment management
- Guix provides multiple tools to manage environment. This chapter
- demonstrate such utilities.
- @menu
- * Guix environment via direnv:: Setup Guix environment with direnv
- @end menu
- @node Guix environment via direnv
- @section Guix environment via direnv
- Guix provides a @samp{direnv} package, which could extend shell after
- directory change. This tool could be used to prepare a pure Guix
- environment.
- The following example provides a shell function for @file{~/.direnvrc}
- file, which could be used from Guix Git repository in
- @file{~/src/guix/.envrc} file to setup a build environment similar to
- described in @pxref{Building from Git,,, guix, GNU Guix Reference
- Manual}.
- Create a @file{~/.direnvrc} with a Bash code:
- @example
- # Thanks <https://github.com/direnv/direnv/issues/73#issuecomment-152284914>
- export_function()
- @{
- local name=$1
- local alias_dir=$PWD/.direnv/aliases
- mkdir -p "$alias_dir"
- PATH_add "$alias_dir"
- local target="$alias_dir/$name"
- if declare -f "$name" >/dev/null; then
- echo "#!$SHELL" > "$target"
- declare -f "$name" >> "$target" 2>/dev/null
- # Notice that we add shell variables to the function trigger.
- echo "$name \$*" >> "$target"
- chmod +x "$target"
- fi
- @}
- use_guix()
- @{
- # Set GitHub token.
- export GUIX_GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- # Unset 'GUIX_PACKAGE_PATH'.
- export GUIX_PACKAGE_PATH=""
- # Recreate a garbage collector root.
- gcroots="$HOME/.config/guix/gcroots"
- mkdir -p "$gcroots"
- gcroot="$gcroots/guix"
- if [ -L "$gcroot" ]
- then
- rm -v "$gcroot"
- fi
- # Miscellaneous packages.
- PACKAGES_MAINTENANCE=(
- direnv
- git
- git:send-email
- git-cal
- gnupg
- guile-colorized
- guile-readline
- less
- ncurses
- openssh
- xdot
- )
- # Environment packages.
- PACKAGES=(help2man guile-sqlite3 guile-gcrypt)
- # Thanks <https://lists.gnu.org/archive/html/guix-devel/2016-09/msg00859.html>
- eval "$(guix environment --search-paths --root="$gcroot" --pure guix --ad-hoc $@{PACKAGES[@@]@} $@{PACKAGES_MAINTENANCE[@@]@} "$@@")"
- # Predefine configure flags.
- configure()
- @{
- ./configure --localstatedir=/var --prefix=
- @}
- export_function configure
- # Run make and optionally build something.
- build()
- @{
- make -j 2
- if [ $# -gt 0 ]
- then
- ./pre-inst-env guix build "$@@"
- fi
- @}
- export_function build
- # Predefine push Git command.
- push()
- @{
- git push --set-upstream origin
- @}
- export_function push
- clear # Clean up the screen.
- git-cal --author='Your Name' # Show contributions calendar.
- # Show commands help.
- echo "
- build build a package or just a project if no argument provided
- configure run ./configure with predefined parameters
- push push to upstream Git repository
- "
- @}
- @end example
- Every project containing @file{.envrc} with a string @code{use guix}
- will have predefined environment variables and procedures.
- Run @command{direnv allow} to setup the environment for the first time.
- @c *********************************************************************
- @node Installing Guix on a Cluster
- @chapter Installing Guix on a Cluster
- @cindex cluster installation
- @cindex high-performance computing, HPC
- @cindex HPC, high-performance computing
- Guix is appealing to scientists and @acronym{HPC, high-performance
- computing} practitioners: it makes it easy to deploy potentially complex
- software stacks, and it lets you do so in a reproducible fashion---you
- can redeploy the exact same software on different machines and at
- different points in time.
- In this chapter we look at how a cluster sysadmin can install Guix for
- system-wide use, such that it can be used on all the cluster nodes, and
- discuss the various tradeoffs@footnote{This chapter is adapted from a
- @uref{https://hpc.guix.info/blog/2017/11/installing-guix-on-a-cluster/,
- blog post published on the Guix-HPC web site in 2017}.}.
- @quotation Note
- Here we assume that the cluster is running a GNU/Linux distro other than
- Guix System and that we are going to install Guix on top of it.
- @end quotation
- @menu
- * Setting Up a Head Node:: The node that runs the daemon.
- * Setting Up Compute Nodes:: Client nodes.
- * Cluster Network Access:: Dealing with network access restrictions.
- * Cluster Disk Usage:: Disk usage considerations.
- * Cluster Security Considerations:: Keeping the cluster secure.
- @end menu
- @node Setting Up a Head Node
- @section Setting Up a Head Node
- The recommended approach is to set up one @emph{head node} running
- @command{guix-daemon} and exporting @file{/gnu/store} over NFS to
- compute nodes.
- Remember that @command{guix-daemon} is responsible for spawning build
- processes and downloads on behalf of clients (@pxref{Invoking
- guix-daemon,,, guix, GNU Guix Reference Manual}), and more generally
- accessing @file{/gnu/store}, which contains all the package binaries
- built by all the users (@pxref{The Store,,, guix, GNU Guix Reference
- Manual}). ``Client'' here refers to all the Guix commands that users
- see, such as @code{guix install}. On a cluster, these commands may be
- running on the compute nodes and we'll want them to talk to the head
- node's @code{guix-daemon} instance.
- To begin with, the head node can be installed following the usual binary
- installation instructions (@pxref{Binary Installation,,, guix, GNU Guix
- Reference Manual}). Thanks to the installation script, this should be
- quick. Once installation is complete, we need to make some adjustments.
- Since we want @code{guix-daemon} to be reachable not just from the head
- node but also from the compute nodes, we need to arrange so that it
- listens for connections over TCP/IP. To do that, we'll edit the systemd
- startup file for @command{guix-daemon},
- @file{/etc/systemd/system/guix-daemon.service}, and add a
- @code{--listen} argument to the @code{ExecStart} line so that it looks
- something like this:
- @example
- ExecStart=/var/guix/profiles/per-user/root/current-guix/bin/guix-daemon --build-users-group=guixbuild --listen=/var/guix/daemon-socket/socket --listen=0.0.0.0
- @end example
- For these changes to take effect, the service needs to be restarted:
- @example
- systemctl daemon-reload
- systemctl restart guix-daemon
- @end example
- @quotation Note
- The @code{--listen=0.0.0.0} bit means that @code{guix-daemon} will
- process @emph{all} incoming TCP connections on port 44146
- (@pxref{Invoking guix-daemon,,, guix, GNU Guix Reference Manual}). This
- is usually fine in a cluster setup where the head node is reachable
- exclusively from the cluster's local area network---you don't want that
- to be exposed to the Internet!
- @end quotation
- The next step is to define our NFS exports in
- @uref{https://linux.die.net/man/5/exports,@file{/etc/exports}} by adding
- something along these lines:
- @example
- /gnu/store *(ro)
- /var/guix *(rw, async)
- /var/log/guix *(ro)
- @end example
- The @file{/gnu/store} directory can be exported read-only since only
- @command{guix-daemon} on the master node will ever modify it.
- @file{/var/guix} contains @emph{user profiles} as managed by @code{guix
- package}; thus, to allow users to install packages with @code{guix
- package}, this must be read-write.
- Users can create as many profiles as they like in addition to the
- default profile, @file{~/.guix-profile}. For instance, @code{guix
- package -p ~/dev/python-dev -i python} installs Python in a profile
- reachable from the @code{~/dev/python-dev} symlink. To make sure that
- this profile is protected from garbage collection---i.e., that Python
- will not be removed from @file{/gnu/store} while this profile exists---,
- @emph{home directories should be mounted on the head node} as well so
- that @code{guix-daemon} knows about these non-standard profiles and
- avoids collecting software they refer to.
- It may be a good idea to periodically remove unused bits from
- @file{/gnu/store} by running @command{guix gc} (@pxref{Invoking guix
- gc,,, guix, GNU Guix Reference Manual}). This can be done by adding a
- crontab entry on the head node:
- @example
- root@@master# crontab -e
- @end example
- @noindent
- ... with something like this:
- @example
- # Every day at 5AM, run the garbage collector to make sure
- # at least 10 GB are free on /gnu/store.
- 0 5 * * 1 /usr/local/bin/guix gc -F10G
- @end example
- We're done with the head node! Let's look at compute nodes now.
- @node Setting Up Compute Nodes
- @section Setting Up Compute Nodes
- First of all, we need compute nodes to mount those NFS directories that
- the head node exports. This can be done by adding the following lines
- to @uref{https://linux.die.net/man/5/fstab,@file{/etc/fstab}}:
- @example
- @var{head-node}:/gnu/store /gnu/store nfs defaults,_netdev,vers=3 0 0
- @var{head-node}:/var/guix /var/guix nfs defaults,_netdev,vers=3 0 0
- @var{head-node}:/var/log/guix /var/log/guix nfs defaults,_netdev,vers=3 0 0
- @end example
- @noindent
- ... where @var{head-node} is the name or IP address of your head node.
- From there on, assuming the mount points exist, you should be able to
- mount each of these on the compute nodes.
- Next, we need to provide a default @command{guix} command that users can
- run when they first connect to the cluster (eventually they will invoke
- @command{guix pull}, which will provide them with their ``own''
- @command{guix} command). Similar to what the binary installation script
- did on the head node, we'll store that in @file{/usr/local/bin}:
- @example
- mkdir -p /usr/local/bin
- ln -s /var/guix/profiles/per-user/root/current-guix/bin/guix \
- /usr/local/bin/guix
- @end example
- We then need to tell @code{guix} to talk to the daemon running on our
- master node, by adding these lines to @code{/etc/profile}:
- @example
- GUIX_DAEMON_SOCKET="guix://@var{head-node}"
- export GUIX_DAEMON_SOCKET
- @end example
- To avoid warnings and make sure @code{guix} uses the right locale, we
- need to tell it to use locale data provided by Guix (@pxref{Application
- Setup,,, guix, GNU Guix Reference Manual}):
- @example
- GUIX_LOCPATH=/var/guix/profiles/per-user/root/guix-profile/lib/locale
- export GUIX_LOCPATH
- # Here we must use a valid locale name. Try "ls $GUIX_LOCPATH/*"
- # to see what names can be used.
- LC_ALL=fr_FR.utf8
- export LC_ALL
- @end example
- For convenience, @code{guix package} automatically generates
- @file{~/.guix-profile/etc/profile}, which defines all the environment
- variables necessary to use the packages---@code{PATH},
- @code{C_INCLUDE_PATH}, @code{PYTHONPATH}, etc. Thus it's a good idea to
- source it from @code{/etc/profile}:
- @example
- GUIX_PROFILE="$HOME/.guix-profile"
- if [ -f "$GUIX_PROFILE/etc/profile" ]; then
- . "$GUIX_PROFILE/etc/profile"
- fi
- @end example
- Last but not least, Guix provides command-line completion notably for
- Bash and zsh. In @code{/etc/bashrc}, consider adding this line:
- @verbatim
- . /var/guix/profiles/per-user/root/current-guix/etc/bash_completion.d/guix
- @end verbatim
- Voilà!
- You can check that everything's in place by logging in on a compute node
- and running:
- @example
- guix install hello
- @end example
- The daemon on the head node should download pre-built binaries on your
- behalf and unpack them in @file{/gnu/store}, and @command{guix install}
- should create @file{~/.guix-profile} containing the
- @file{~/.guix-profile/bin/hello} command.
- @node Cluster Network Access
- @section Network Access
- Guix requires network access to download source code and pre-built
- binaries. The good news is that only the head node needs that since
- compute nodes simply delegate to it.
- It is customary for cluster nodes to have access at best to a
- @emph{white list} of hosts. Our head node needs at least
- @code{ci.guix.gnu.org} in this white list since this is where it gets
- pre-built binaries from by default, for all the packages that are in
- Guix proper.
- Incidentally, @code{ci.guix.gnu.org} also serves as a
- @emph{content-addressed mirror} of the source code of those packages.
- Consequently, it is sufficient to have @emph{only}
- @code{ci.guix.gnu.org} in that white list.
- Software packages maintained in a separate repository such as one of the
- various @uref{https://hpc.guix.info/channels, HPC channels} are of
- course unavailable from @code{ci.guix.gnu.org}. For these packages, you
- may want to extend the white list such that source and pre-built
- binaries (assuming this-party servers provide binaries for these
- packages) can be downloaded. As a last resort, users can always
- download source on their workstation and add it to the cluster's
- @file{/gnu/store}, like this:
- @verbatim
- GUIX_DAEMON_SOCKET=ssh://compute-node.example.org \
- guix download http://starpu.gforge.inria.fr/files/starpu-1.2.3/starpu-1.2.3.tar.gz
- @end verbatim
- The above command downloads @code{starpu-1.2.3.tar.gz} @emph{and} sends
- it to the cluster's @code{guix-daemon} instance over SSH.
- Air-gapped clusters require more work. At the moment, our suggestion
- would be to download all the necessary source code on a workstation
- running Guix. For instance, using the @option{--sources} option of
- @command{guix build} (@pxref{Invoking guix build,,, guix, GNU Guix
- Reference Manual}), the example below downloads all the source code the
- @code{openmpi} package depends on:
- @example
- $ guix build --sources=transitive openmpi
- @dots{}
- /gnu/store/xc17sm60fb8nxadc4qy0c7rqph499z8s-openmpi-1.10.7.tar.bz2
- /gnu/store/s67jx92lpipy2nfj5cz818xv430n4b7w-gcc-5.4.0.tar.xz
- /gnu/store/npw9qh8a46lrxiwh9xwk0wpi3jlzmjnh-gmp-6.0.0a.tar.xz
- /gnu/store/hcz0f4wkdbsvsdky3c0vdvcawhdkyldb-mpfr-3.1.5.tar.xz
- /gnu/store/y9akh452n3p4w2v631nj0injx7y0d68x-mpc-1.0.3.tar.gz
- /gnu/store/6g5c35q8avfnzs3v14dzl54cmrvddjm2-glibc-2.25.tar.xz
- /gnu/store/p9k48dk3dvvk7gads7fk30xc2pxsd66z-hwloc-1.11.8.tar.bz2
- /gnu/store/cry9lqidwfrfmgl0x389cs3syr15p13q-gcc-5.4.0.tar.xz
- /gnu/store/7ak0v3rzpqm2c5q1mp3v7cj0rxz0qakf-libfabric-1.4.1.tar.bz2
- /gnu/store/vh8syjrsilnbfcf582qhmvpg1v3rampf-rdma-core-14.tar.gz
- …
- @end example
- (In case you're wondering, that's more than 320@ MiB of
- @emph{compressed} source code.)
- We can then make a big archive containing all of this (@pxref{Invoking
- guix archive,,, guix, GNU Guix Reference Manual}):
- @verbatim
- $ guix archive --export \
- `guix build --sources=transitive openmpi` \
- > openmpi-source-code.nar
- @end verbatim
- @dots{} and we can eventually transfer that archive to the cluster on
- removable storage and unpack it there:
- @verbatim
- $ guix archive --import < openmpi-source-code.nar
- @end verbatim
- This process has to be repeated every time new source code needs to be
- brought to the cluster.
- As we write this, the research institutes involved in Guix-HPC do not
- have air-gapped clusters though. If you have experience with such
- setups, we would like to hear feedback and suggestions.
- @node Cluster Disk Usage
- @section Disk Usage
- @cindex disk usage, on a cluster
- A common concern of sysadmins' is whether this is all going to eat a lot
- of disk space. If anything, if something is going to exhaust disk
- space, it's going to be scientific data sets rather than compiled
- software---that's our experience with almost ten years of Guix usage on
- HPC clusters. Nevertheless, it's worth taking a look at how Guix
- contributes to disk usage.
- First, having several versions or variants of a given package in
- @file{/gnu/store} does not necessarily cost much, because
- @command{guix-daemon} implements deduplication of identical files, and
- package variants are likely to have a number of common files.
- As mentioned above, we recommend having a cron job to run @code{guix gc}
- periodically, which removes @emph{unused} software from
- @file{/gnu/store}. However, there's always a possibility that users will
- keep lots of software in their profiles, or lots of old generations of
- their profiles, which is ``live'' and cannot be deleted from the
- viewpoint of @command{guix gc}.
- The solution to this is for users to regularly remove old generations of
- their profile. For instance, the following command removes generations
- that are more than two-month old:
- @example
- guix package --delete-generations=2m
- @end example
- Likewise, it's a good idea to invite users to regularly upgrade their
- profile, which can reduce the number of variants of a given piece of
- software stored in @file{/gnu/store}:
- @example
- guix pull
- guix upgrade
- @end example
- As a last resort, it is always possible for sysadmins to do some of this
- on behalf of their users. Nevertheless, one of the strengths of Guix is
- the freedom and control users get on their software environment, so we
- strongly recommend leaving users in control.
- @node Cluster Security Considerations
- @section Security Considerations
- @cindex security, on a cluster
- On an HPC cluster, Guix is typically used to manage scientific software.
- Security-critical software such as the operating system kernel and
- system services such as @code{sshd} and the batch scheduler remain under
- control of sysadmins.
- The Guix project has a good track record delivering security updates in
- a timely fashion (@pxref{Security Updates,,, guix, GNU Guix Reference
- Manual}). To get security updates, users have to run @code{guix pull &&
- guix upgrade}.
- Because Guix uniquely identifies software variants, it is easy to see if
- a vulnerable piece of software is in use. For instance, to check whether
- the glibc@ 2.25 variant without the mitigation patch against
- ``@uref{https://www.qualys.com/2017/06/19/stack-clash/stack-clash.txt,Stack
- Clash}'', one can check whether user profiles refer to it at all:
- @example
- guix gc --referrers /gnu/store/…-glibc-2.25
- @end example
- This will report whether profiles exist that refer to this specific
- glibc variant.
- @c *********************************************************************
- @node Acknowledgments
- @chapter Acknowledgments
- Guix is based on the @uref{https://nixos.org/nix/, Nix package manager},
- which was designed and
- implemented by Eelco Dolstra, with contributions from other people (see
- the @file{nix/AUTHORS} file in Guix.) Nix pioneered functional package
- management, and promoted unprecedented features, such as transactional
- package upgrades and rollbacks, per-user profiles, and referentially
- transparent build processes. Without this work, Guix would not exist.
- The Nix-based software distributions, Nixpkgs and NixOS, have also been
- an inspiration for Guix.
- GNU@tie{}Guix itself is a collective work with contributions from a
- number of people. See the @file{AUTHORS} file in Guix for more
- information on these fine people. The @file{THANKS} file lists people
- who have helped by reporting bugs, taking care of the infrastructure,
- providing artwork and themes, making suggestions, and more---thank you!
- This document includes adapted sections from articles that have
- previously been published on the Guix blog at
- @uref{https://guix.gnu.org/blog} and on the Guix-HPC blog at
- @uref{https://hpc.guix.info/blog}.
- @c *********************************************************************
- @node GNU Free Documentation License
- @appendix GNU Free Documentation License
- @cindex license, GNU Free Documentation License
- @include fdl-1.3.texi
- @c *********************************************************************
- @node Concept Index
- @unnumbered Concept Index
- @printindex cp
- @bye
- @c Local Variables:
- @c ispell-local-dictionary: "american";
- @c End:
|