[{"data":1,"prerenderedAt":911},["ShallowReactive",2],{"post-\u002Fposts\u002Fhow-to-use-terraform-with-digitalocean":3,"post-author-garywoodfine":518,"post-aside-video-none":6,"\u002Fposts\u002Fhow-to-use-terraform-with-digitalocean-surround":527,"navigation":538,"authors":586,"author-garywoodfine":615,"post-aside-related-candidates":616,"content-section-services":887,"content-section-products":890,"content-section-company":893,"legal-link":895},{"id":4,"title":5,"aside":6,"author":7,"body":8,"category":494,"date":495,"description":496,"extension":497,"featureImage":498,"meta":500,"navigation":502,"path":503,"seo":504,"sitemap":505,"slug":6,"stem":515,"subtitle":516,"summary":496,"tags":6,"updated":6,"video":6,"__hash__":517},"posts\u002Fposts\u002Fhow-to-use-terraform-with-digitalocean.md","How to use Terraform with DigitalOcean",null,"garywoodfine",{"type":9,"value":10,"toc":485},"minimark",[11,15,18,28,33,36,39,42,47,50,79,83,92,95,139,142,156,159,164,168,174,181,192,238,251,294,298,301,308,315,329,332,341,345,358,363,370,376,382,407,413,446,471,475,478,481],[12,13,14],"p",{},"Here at threenine.io we are a small team that takes on big projects, and because of these we have a strong focus on keeping\nthings simple, lean and agile. Over the years, we have developed and evolved our own processes.  Often, completely\ndisregarding the text book best practices, because quite frankly they just don't work. That sentence alone\nrequires an entire series of articles which we won't go into here, but most likely will in other articles.",[12,16,17],{},"With all those points said, we are always looking for ways to optimise and improve the way we work and can get things\nquickly and efficiently. One of these approaches we have adopted is the Infrastructure as Code methodology. Our tool of\nchoice over the years has become Terraform, especially when working with Cloud Providers.",[12,19,20,27],{},[21,22,26],"a",{"href":23,"rel":24},"https:\u002F\u002Fwww.terraform.io\u002F",[25],"nofollow","Terraform"," is a tool for building and managing infrastructure in an organised way. You can use it to manage\nvirtual machines, containers, Load Balancers, and even DNS entries, in addition to a large variety of services offered by\nother providers. Terraform uses a command-line interface and can run from your desktop or a remote server.",[29,30],"digital-ocean",{"icon":31,"link":32},"hugeicons:api","https:\u002F\u002Fm.do.co\u002Fc\u002F93ff23d34ca8",[12,34,35],{},"Terraform works by reading configuration files that describe the components that make up your application environment\nor datacenter. Based on the configuration, it generates an execution plan that describes what it will do to reach the\ndesired state. You then use Terraform to execute this plan to build the infrastructure. When changes to the\nconfiguration occur, Terraform can generate and execute incremental plans to update the existing infrastructure to the\nnewly described state.",[12,37,38],{},"Although, AWS and Azure, seem to be the leaders in the Enterprise Cloud Native game, we have developed a strong\npreference to using DigitalOcean.  In our experiences, for the smaller companies, start ups and bootstrappers, the so\ncalled leading platforms have have really complicated billing and unpredictable billing practices and its not always\neasy to work out and stick to a budget. This is where in my opinion Digital Ocean delivers its true value along with\nproviding a great scalable and performant platform to build your new ideas on.",[12,40,41],{},"This post will guide you through the process of install Terraform and configuring it to work on your Linux\ndevelopment workstation.",[43,44,46],"h3",{"id":45},"prerequisites","Prerequisites",[12,48,49],{},"In order to complete the steps in this article, there are a few things you need to have in place.",[51,52,53,67,70],"ul",{},[54,55,56,57,61,62,66],"li",{},"A ",[21,58,60],{"href":32,"rel":59},[25],"Digital Ocean Account",", if you do not have one yet, Sign up for a new  ",[21,63,65],{"href":32,"rel":64},[25],"Digital Ocean account"," and get free credit.",[54,68,69],{},"We are a solely Linux-based software development house, so we recommend that you be using Linux to following along.",[54,71,72,73,78],{},"We recommend using ",[21,74,77],{"href":75,"rel":76},"https:\u002F\u002Fdocs.brew.sh\u002FHomebrew-on-Linux",[25],"Homebrew package manager"," when installing developer tools\nit seems to be more frequently updated than the official repositories, when it comes to developer tools.",[43,80,82],{"id":81},"how-to-install-terraform","How to install Terraform",[12,84,85,86,91],{},"The official Terraform site has some pretty good instructions on ",[21,87,90],{"href":88,"rel":89},"https:\u002F\u002Fdeveloper.hashicorp.com\u002Fterraform\u002Ftutorials\u002Faws-get-started\u002Finstall-cli",[25],"how to install to terraform",",\nhowever we have developed a strong preference to make use of the Homebrew package manager approach. In fact that is the\napproach we take internally without exceptions.",[12,93,94],{},"The first step is to ensure you reference the official Hashicorp tap, then install the package as detailed in the script\nbelow",[96,97,102],"pre",{"className":98,"code":99,"language":100,"meta":101,"style":101},"language-shell shiki shiki-themes material-theme-lighter monokai monokai monokai","brew tap hashicorp\u002Ftap\n# install terraform\nbrew install hashicorp\u002Ftap\u002Fterraform\n","shell","",[103,104,105,121,128],"code",{"__ignoreMap":101},[106,107,110,114,118],"span",{"class":108,"line":109},"line",1,[106,111,113],{"class":112},"sC-bC","brew",[106,115,117],{"class":116},"sKdu0"," tap",[106,119,120],{"class":116}," hashicorp\u002Ftap\n",[106,122,124],{"class":108,"line":123},2,[106,125,127],{"class":126},"sw-b4","# install terraform\n",[106,129,131,133,136],{"class":108,"line":130},3,[106,132,113],{"class":112},[106,134,135],{"class":116}," install",[106,137,138],{"class":116}," hashicorp\u002Ftap\u002Fterraform\n",[12,140,141],{},"Once installed you can verify that Terraform has been installed by checking the version as follows",[96,143,145],{"className":98,"code":144,"language":100,"meta":101,"style":101},"terraform --version\n",[103,146,147],{"__ignoreMap":101},[106,148,149,152],{"class":108,"line":109},[106,150,151],{"class":112},"terraform",[106,153,155],{"class":154},"sbSe9"," --version\n",[12,157,158],{},"This should return the version details similar to the screen shot below",[160,161],"content-image",{"image":162,"title":163},"blog\u002Fterraform-version_zrpkmm","Terraform Version",[43,165,167],{"id":166},"how-to-set-up-a-terraform-alias-on-linux","How to set up a Terraform alias on Linux",[12,169,170,171,173],{},"The following step is entirely optional, and if we perfectly honest is only for the really lazy developers who want to\nsave a few additional keystrokes a day. However, if your typing is as bad as mine, you find yourself having to type a\nlong word like ",[103,172,151],{}," difficult without making a typo then you can create a simple alias to help.",[12,175,176,177,180],{},"It is pretty standard on must Linux distros to have e a file in my home directory named ",[103,178,179],{},".bash_aliases"," which is use to\ndefine all sorts of aliases on your machine.  Aliases in Linux are pretty cool things to use, because they let you\ndefine your own commands — or command shortcuts — so you can customise the command line and make it work the way you\nwant it to work.",[12,182,183,184,187,188,191],{},"If you take a look at your ",[103,185,186],{},".bashrc"," file you may most likely find the lines below that automatically loads the\n",[103,189,190],{},"bash_aliases"," everytime you start a terminal session",[96,193,195],{"className":98,"code":194,"language":100,"meta":101,"style":101},"if [ -f ~\u002F.bash_aliases ]; then\n    . ~\u002F.bash_aliases\nfi\n",[103,196,197,224,233],{"__ignoreMap":101},[106,198,199,203,207,211,214,218,221],{"class":108,"line":109},[106,200,202],{"class":201},"s7SBB","if",[106,204,206],{"class":205},"s8B1f"," [",[106,208,210],{"class":209},"sb10O"," -f",[106,212,213],{"class":209}," ~",[106,215,217],{"class":216},"sRVMn","\u002F.bash_aliases ",[106,219,220],{"class":205},"];",[106,222,223],{"class":201}," then\n",[106,225,226,230],{"class":108,"line":123},[106,227,229],{"class":228},"sSYhn","    .",[106,231,232],{"class":116}," ~\u002F.bash_aliases\n",[106,234,235],{"class":108,"line":130},[106,236,237],{"class":201},"fi\n",[12,239,240,241,243,244,247,248,250],{},"This will enable you to do define an alias in the ",[103,242,179],{}," file as follows to make the ",[103,245,246],{},"tf"," be the ",[103,249,151],{},"\ncommand. To do this you can simply execute the following commands in your terminal window",[96,252,254],{"className":98,"code":253,"language":100,"meta":101,"style":101},"echo \"alias tf='terraform'\" | tee -a .bash_aliases \n. ~\u002F.bashrc\n",[103,255,256,286],{"__ignoreMap":101},[106,257,258,261,265,268,271,274,277,280,283],{"class":108,"line":109},[106,259,260],{"class":228},"echo",[106,262,264],{"class":263},"sxJtY"," \"",[106,266,267],{"class":116},"alias tf='terraform'",[106,269,270],{"class":263},"\"",[106,272,273],{"class":209}," |",[106,275,276],{"class":112}," tee",[106,278,279],{"class":154}," -a",[106,281,282],{"class":116}," .bash_aliases",[106,284,285],{"class":216}," \n",[106,287,288,291],{"class":108,"line":123},[106,289,290],{"class":228},".",[106,292,293],{"class":116}," ~\u002F.bashrc\n",[43,295,297],{"id":296},"install-the-digitalocean-cli","Install the DigitalOcean CLI",[12,299,300],{},"We will also need to install doctl the Digital Ocean Command Line Tool. allows you to interact with the DigitalOcean API\nvia the command line. It supports most functionality found in the control panel. You can create, configure, and destroy\nDigital Ocean resources like Droplets, Kubernetes clusters, firewalls, load balancers, database clusters, domains, and more.",[12,302,303,304],{},"We mentioned previously in this article that you will need a Digital ocean account, you can get one if you haven't\nalready by following this link and as a bonus you will get $200 free credit for 60 days, ",[21,305,307],{"href":32,"rel":306},[25],"Sign up for DigitalOcean",[12,309,310,311,314],{},"Previously, we installed Terraform using Homebrew, it will come as no surprise then when we recommend using Homebrew\nto install the DigitalOcean CLI, also known as ",[103,312,313],{},"doctl",". This can simply done by executing the following command in your\nterminal window.",[96,316,318],{"className":98,"code":317,"language":100,"meta":101,"style":101},"brew install doctl\n",[103,319,320],{"__ignoreMap":101},[106,321,322,324,326],{"class":108,"line":109},[106,323,113],{"class":112},[106,325,135],{"class":116},[106,327,328],{"class":116}," doctl\n",[12,330,331],{},"Once the install has completed you should be able to verify that it was successful, and execute the following command\nand presented with a number options that are now available to you.",[96,333,335],{"className":98,"code":334,"language":100,"meta":101,"style":101},"doctl\n",[103,336,337],{"__ignoreMap":101},[106,338,339],{"class":108,"line":109},[106,340,334],{"class":112},[160,342],{"image":343,"title":344},"blog\u002Fdoctl-install_v7o046","DigitalOcean CLI installed",[346,347,348],"top-tip",{},[349,350,351],"template",{"v-slot:message":101},[12,352,353],{},[21,354,357],{"href":355,"rel":356},"https:\u002F\u002Fdocs.digitalocean.com\u002Freference\u002Fapi\u002Fcreate-personal-access-token\u002F",[25],"Create a personal access token for your\ndigital ocean account",[359,360,362],"h2",{"id":361},"add-your-access-token-to-your-environment-variables","Add your access token to your Environment Variables",[12,364,365,366,369],{},"Although we have managed to login to DigitalOcean CLI with our access token, we still need to be able to share and\nuse our DigitalOcean token with terraform. To do this, we typically follow steps similar to what we did with the aliases,\nin that we are going to create a ",[103,367,368],{},".bash_variables"," file to store our environment variables.",[12,371,372,373,375],{},"One reason we like to do this, is mostly to do with organisation.  I hate having to open my  ",[103,374,186],{},"  and try read through\nit all to find a variable and change its values.  I prefer to have a dedicated file for that, and therefore it is also\neasier to back that file up with my variable values.",[12,377,378,379,381],{},"In the line below, we'll create and add our personal access token to ",[103,380,368],{}," file.",[96,383,385],{"className":98,"code":384,"language":100,"meta":101,"style":101},"echo \"export DIGITALOCEAN_TOKEN=\u003Cpaste your token here>\" | tee -a .bash_variables \n",[103,386,387],{"__ignoreMap":101},[106,388,389,391,393,396,398,400,402,404],{"class":108,"line":109},[106,390,260],{"class":228},[106,392,264],{"class":263},[106,394,395],{"class":116},"export DIGITALOCEAN_TOKEN=\u003Cpaste your token here>",[106,397,270],{"class":263},[106,399,273],{"class":209},[106,401,276],{"class":112},[106,403,279],{"class":154},[106,405,406],{"class":116}," .bash_variables\n",[12,408,409,410,412],{},"With file now in place, you can add the following lines to your ",[103,411,186],{}," file, to load the file if it exists.",[96,414,416],{"className":98,"code":415,"language":100,"meta":101,"style":101},"if [ -f ~\u002F.bash_variables ]; then\n    . ~\u002F.bash_variables\nfi\n",[103,417,418,435,442],{"__ignoreMap":101},[106,419,420,422,424,426,428,431,433],{"class":108,"line":109},[106,421,202],{"class":201},[106,423,206],{"class":205},[106,425,210],{"class":209},[106,427,213],{"class":209},[106,429,430],{"class":216},"\u002F.bash_variables ",[106,432,220],{"class":205},[106,434,223],{"class":201},[106,436,437,439],{"class":108,"line":123},[106,438,229],{"class":228},[106,440,441],{"class":116}," ~\u002F.bash_variables\n",[106,443,444],{"class":108,"line":130},[106,445,237],{"class":201},[346,447,448],{},[349,449,450,453,465],{"v-slot:message":101},[12,451,452],{},"The Digital Ocean Terrafrom provider, automatically looks for and uses either of the following Environment Variables if\nthey exist",[51,454,455,460],{},[54,456,457],{},[103,458,459],{},"DIGITALOCEAN_TOKEN",[54,461,462],{},[103,463,464],{},"DIGITALOCEAN_ACCESS_TOKEN",[12,466,467,468],{},"So you don't have to pass them in when using ",[103,469,470],{},"terraform apply",[43,472,474],{"id":473},"summary","Summary",[12,476,477],{},"At threenine.io, we are a small yet dynamic team, we emphasise simplicity, efficiency, and agility, often deviating from\ntextbook best practices to evolve our processes. We're constantly looking to optimise our workflow and have embraced\nInfrastructure as Code, specifically using Terraform for managing cloud infrastructure, especially with DigitalOcean.",[12,479,480],{},"This post provides instructions on installing and setting up Terraform on a Linux development machine, highlighting\nthe advantages of using Homebrew for installation. Additionally, it guides on setting up a convenient Terraform alias\nand installing the DigitalOcean CLI (doctl). Steps for creating and managing environment variables for DigitalOcean\ntokens are also covered, emphasising the ease and organisation of using separate files for aliases and variables. The\ndetailed instructions aim to streamline the setup process, making it easier for developers to efficiently manage\ninfrastructure on DigitalOcean.",[482,483,484],"style",{},"html pre.shiki code .sC-bC, html code.shiki .sC-bC{--shiki-light:#E2931D;--shiki-default:#A6E22E;--shiki-dark:#A6E22E;--shiki-sepia:#A6E22E}html pre.shiki code .sKdu0, html code.shiki .sKdu0{--shiki-light:#91B859;--shiki-default:#E6DB74;--shiki-dark:#E6DB74;--shiki-sepia:#E6DB74}html pre.shiki code .sw-b4, html code.shiki .sw-b4{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#88846F;--shiki-default-font-style:inherit;--shiki-dark:#88846F;--shiki-dark-font-style:inherit;--shiki-sepia:#88846F;--shiki-sepia-font-style:inherit}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sbSe9, html code.shiki .sbSe9{--shiki-light:#91B859;--shiki-default:#AE81FF;--shiki-dark:#AE81FF;--shiki-sepia:#AE81FF}html pre.shiki code .s7SBB, html code.shiki .s7SBB{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#F92672;--shiki-default-font-style:inherit;--shiki-dark:#F92672;--shiki-dark-font-style:inherit;--shiki-sepia:#F92672;--shiki-sepia-font-style:inherit}html pre.shiki code .s8B1f, html code.shiki .s8B1f{--shiki-light:#39ADB5;--shiki-default:#F8F8F2;--shiki-dark:#F8F8F2;--shiki-sepia:#F8F8F2}html pre.shiki code .sb10O, html code.shiki .sb10O{--shiki-light:#39ADB5;--shiki-default:#F92672;--shiki-dark:#F92672;--shiki-sepia:#F92672}html pre.shiki code .sRVMn, html code.shiki .sRVMn{--shiki-light:#90A4AE;--shiki-default:#F8F8F2;--shiki-dark:#F8F8F2;--shiki-sepia:#F8F8F2}html pre.shiki code .sSYhn, html code.shiki .sSYhn{--shiki-light:#6182B8;--shiki-default:#66D9EF;--shiki-dark:#66D9EF;--shiki-sepia:#66D9EF}html pre.shiki code .sxJtY, html code.shiki .sxJtY{--shiki-light:#39ADB5;--shiki-default:#E6DB74;--shiki-dark:#E6DB74;--shiki-sepia:#E6DB74}",{"title":101,"searchDepth":123,"depth":123,"links":486},[487,488,489,490,491],{"id":45,"depth":130,"text":46},{"id":81,"depth":130,"text":82},{"id":166,"depth":130,"text":167},{"id":296,"depth":130,"text":297},{"id":361,"depth":123,"text":362,"children":492},[493],{"id":473,"depth":130,"text":474},"development","2024-10-05","A tutorial on how to configure your local environment with Terraform and DigitalOcean CLI","md",{"url":499,"title":5},"v1690313893\u002Fterraform-header_ixmkgg",{"publishDateTime":501},"2024-10-05:17:30",true,"\u002Fposts\u002Fhow-to-use-terraform-with-digitalocean",{"title":5,"description":496},{"loc":503,"lastmod":495,"changefreq":506,"priority":507,"images":508},"monthly",0.8,[509,511,513],{"loc":510},"https:\u002F\u002Fres.cloudinary.com\u002Fthreenine-co-uk\u002Fimage\u002Fupload\u002Ff_jpg,w_1200\u002Fv1690313893\u002Fterraform-header_ixmkgg",{"loc":512},"https:\u002F\u002Fres.cloudinary.com\u002Fthreenine-co-uk\u002Fimage\u002Fupload\u002Ff_jpg,w_1200\u002Fblog\u002Fterraform-version_zrpkmm",{"loc":514},"https:\u002F\u002Fres.cloudinary.com\u002Fthreenine-co-uk\u002Fimage\u002Fupload\u002Ff_jpg,w_1200\u002Fblog\u002Fdoctl-install_v7o046","posts\u002Fhow-to-use-terraform-with-digitalocean","Using remote state to store terraform state files in DigitalOcean","IqJBW2A9o0kRXmSJfW8_7Xonvq3dmV5CbLUuzFLYX0w",{"name":519,"to":520,"avatar":521,"sameAs":522},"Gary Woodfine","https:\u002F\u002Fgarywoodfine.com","garywoodfine_tlccjw",[523,524,525,526],"https:\u002F\u002Fgithub.com\u002Fgarywoodfine","https:\u002F\u002Fwww.youtube.com\u002F@Threenineio","https:\u002F\u002Fnjump.me\u002Fnpub1a3jz7w9laar2k77dkkh2rhxunr9zpja5emrl5yrxetamt29swqyqmmt32y","nostr:npub1a3jz7w9laar2k77dkkh2rhxunr9zpja5emrl5yrxetamt29swqyqmmt32y",[528,533],{"title":529,"path":530,"stem":531,"description":532,"children":-1},"How to use layouts and pages in Nuxt","\u002Fposts\u002Fhow-to-use-layouts-and-pages-in-nuxt","posts\u002Fhow-to-use-layouts-and-pages-in-nuxt","Explore how to use layouts and pages in your Nuxt Application",{"title":534,"path":535,"stem":536,"description":537,"children":-1},"What are Web Sockets","\u002Fposts\u002Fwhat-are-web-sockets","posts\u002Fwhat-are-web-sockets","WebSockets are a bi-directional, full duplex communications protocol initiated over HTTP. They are commonly used in modern web applications for streaming data and other asynchronous traffic.",{"id":539,"extension":540,"items":541,"meta":583,"stem":584,"__hash__":585},"navigation\u002Fnavigation.yaml","yaml",[542,555,568,576],{"label":543,"children":544},"products",[545,550],{"label":546,"icon":547,"description":548,"to":549},"Diogel","material-symbols:preview","Keep your Nostr identity in your hands, in your browser, on your phone or on your own server.","\u002Fproducts\u002Fdiogel",{"label":551,"icon":552,"description":553,"to":554},"Nostrfi","i-lucide-radio-tower","Nostr relay, storage and backend-service infrastructure for builders and operators.","\u002Fproducts\u002Fnostrfi",{"label":556,"children":557},"services",[558,563],{"label":559,"description":560,"icon":561,"to":562},"Nostr product development","Focused engineering support for teams building Nostr-native products, tools and protocol-aware user experiences.","game-icons:ostrich","\u002Fservices\u002Fnostr-product-development",{"label":564,"description":565,"icon":566,"to":567},"Bitcoin product development","Engineering for Bitcoin payments, wallet-connected flows and products where users hold their own keys.","bx:bxl-bitcoin","\u002Fservices\u002Fbitcoin-product-development",{"label":569,"children":570},"company",[571],{"label":572,"icon":573,"description":574,"to":575},"About","i-lucide-file-text","What we believe, what we build and how we work.","\u002Fcompany\u002Fabout",{"label":577,"children":578},"resources",[579],{"label":580,"icon":573,"description":581,"to":582},"Blog","Practical Bitcoin, Nostr and product engineering guides.","https:\u002F\u002Fthreenine.blog",{},"navigation","n-Xc9COCwoCHJiMCeBNLauHtuhxcGol-wu9S2og3Rqs",{"id":587,"title":519,"avatar":521,"body":588,"description":592,"extension":497,"meta":607,"name":519,"navigation":502,"path":608,"role":609,"sameAs":610,"seo":611,"stem":612,"summary":613,"to":520,"username":7,"__hash__":614},"authors\u002Fauthors\u002FGary Woodfine.md",{"type":9,"value":589,"toc":605},[590,593,596,599,602],[12,591,592],{},"Polyglot software engineer with extensive experience in software engineering, with a passion to build great scalable software to solve complex business problems. A track record in developing high-performance backend systems, optimizing architecture, and ensuring continuous availability of critical APIs.",[12,594,595],{},"I'm an independent software developer, vendor, architect, consultant, blogger, Bitcoin & Nostr Enthusiast. I've provided software development expertise and helped augment software development skills and teams for a number of startups, product companies, corporate IT shops, and consulting firms.",[12,597,598],{},"I started out in the software world back in 1995, building websites with HoTMetaL Pro & ASP and moved on to building web apps with .NET when it released in Beta in 2001, since then, I've shipped systems in just about every industry.",[12,600,601],{},"Along my journey, I have also shipped various platforms & products in a number of other programming languages or software development frameworks that have had their moments in the sun, but somehow I have always made way back to C# & .Net.",[12,603,604],{},"Over the years, I've strived to improve how I and my teams deliver value to the clients, customers, and end-users. That has led me down the path of exploring Agile, Domain-Driven Design, REST, messaging, distributed systems, and anything else I thought could help.",{"title":101,"searchDepth":123,"depth":123,"links":606},[],{},"\u002Fauthors\u002Fgary-woodfine","Managing Director",[523,524,525,526],{"title":519,"description":592},"authors\u002FGary Woodfine","independent software developer, vendor, architect, consultant, blogger, Bitcoin & Nostr Enthusiast. I've provided software development expertise and helped augment software development skills and teams for a number of startups, product companies, corporate IT shops, and consulting firms.","30ZWJ-6T2g8S0kLLgUhZWA7_QFUOpa5CElif7tAhsLo",{"title":519,"name":519,"role":609,"summary":613,"avatar":521,"username":7,"to":520},[617,629,640,647,654,661,672,681,687,694,700,707,717,726,732,738,743,748,757,763,767,773,777,781,783,788,793,798,804,809,816,825,831,836,844,849,853,858,863,867,873,878,882],{"path":618,"title":619,"date":620,"tags":621,"category":622,"featureImage":627},"\u002Fposts\u002Fwhat-is-a-nostr-client","What is a Nostr client?","2026-10-26",[622,623,624,625,626],"nostr","nostr-client","privacy","keys","getting-started",{"url":628,"title":619},"v1690313893\u002Fnostr-logo_hwrql1",{"path":630,"title":631,"date":632,"tags":633,"category":622,"featureImage":638},"\u002Fposts\u002Fhow-to-choose-nostr-relays","How to Choose Nostr Relays","2026-04-11",[622,634,624,635,636,637],"relay","security","nostr-relays","censorship-resistance",{"url":628,"title":639},"How to choose nostr relays",{"path":641,"title":642,"date":632,"tags":643,"category":622,"featureImage":646},"\u002Fposts\u002Fnostr-relays-privacy-and-security","Nostr Relays, Privacy, and Security",[622,634,624,635,644,645],"key-management","nostr-relay",{"url":628,"title":642},{"path":648,"title":649,"date":632,"tags":650,"category":622,"featureImage":652},"\u002Fposts\u002Fwhat-is-a-nostr-relay","What is a Nostr Relay?",[622,634,624,637,651,645],"decentralization",{"url":628,"title":653}," What is a Nostr Relay?",{"path":655,"title":656,"date":657,"tags":658,"category":622,"featureImage":660},"\u002Fposts\u002Fwhy-nostr-keys-better-privacy","Why Nostr keys and identity are better for privacy","2026-04-06",[622,624,659,635],"identity",{"url":628,"title":656},{"path":662,"title":663,"date":664,"tags":665,"category":622,"featureImage":671},"\u002Fposts\u002Fbest-nostr-browser-extensions-2026","Best Nostr Browser Extensions (2026): Complete Comparison","2026-03-24",[622,666,667,635,668,669,670],"browser-extension","nip-07","comparison","porwr","diogel",{"url":628,"title":663},{"path":673,"title":674,"date":664,"tags":675,"category":622,"featureImage":678},"\u002Fposts\u002Fhow-to-get-started-with-porwr","Getting Started with Nostr: Porwr Setup Guide (2026)",[676,624,622,669,670,677,667,666],"social","cryptography",{"url":679,"title":680},"v1690313893\u002Fblog\u002Fdiogel-product-header_x3az6t","Porwr Browser Extension",{"path":682,"title":683,"date":684,"tags":685,"category":622,"featureImage":686},"\u002Fposts\u002Fhow-to-manage-keys-for-nostr","How to manage keys for Nostr","2025-12-15",[622,625,624,635],{"url":628,"title":683},{"path":688,"title":689,"date":684,"tags":690,"category":622,"featureImage":693},"\u002Fposts\u002Fhow-to-self-host-your-nip-05-identity","How to self-host your NIP-05 identity",[622,691,624,692],"nip-05","self-hosting",{"url":628,"title":689},{"path":695,"title":696,"date":697,"tags":6,"category":624,"featureImage":698},"\u002Fposts\u002Fwhy-privacy-is-a-fundamental-human-right","Why privacy is a fundamental human right","2025-12-09",{"url":699,"title":696},"v1690313893\u002Fprivacy-header_exiblo",{"path":701,"title":702,"date":703,"tags":6,"category":704,"featureImage":705},"\u002Fposts\u002Fhow-government-monetary-policy-erodes-the-value-of-money","How government monetary policy erodes the value of money","2025-12-01","bitcoin",{"url":706,"title":702},"v1719908027\u002Fbitcoin_szcm1m",{"path":708,"title":709,"date":710,"tags":711,"category":704,"featureImage":715},"\u002Fposts\u002Fbitaxe-touch-genesis-batch","Bitaxe Touch Genesis Batch","2025-07-23",[712,713,714],"bitaxe","mining","solo",{"url":716,"title":709},"v1690313878\u002Fbitaxe-touch_c6qrjd",{"path":718,"title":719,"date":720,"tags":721,"category":704,"featureImage":725},"\u002Fposts\u002Fbitcoin-is-not-a-ponzi-scheme","Bitcoin is not a Ponzi Scheme","2025-07-22",[722,723,724],"ponzi","economics","investment",{"url":706,"title":719},{"path":727,"title":728,"date":720,"tags":729,"category":704,"featureImage":731},"\u002Fposts\u002Fgetting-started-with-public-pool-mining","Getting started with Public Pool Mining",[713,714,730],"lottery",{"url":706,"title":728},{"path":733,"title":734,"date":735,"tags":736,"category":704,"featureImage":737},"\u002Fposts\u002Fgetting-started-with-solo-mining","Getting started with solo mining","2025-07-19",[712,713,714,730],{"url":706,"title":734},{"path":739,"title":740,"date":735,"tags":741,"category":704,"featureImage":742},"\u002Fposts\u002Fwhat-is-bitcoin-mining","What is Bitcoin mining",[713,704],{"url":706,"title":740},{"path":744,"title":745,"date":735,"tags":746,"category":704,"featureImage":747},"\u002Fposts\u002Fwhat-is-solo-mining","What is solo mining",[714],{"url":706,"title":745},{"path":749,"title":750,"date":751,"tags":752,"category":704,"featureImage":755},"\u002Fposts\u002Fhow-to-run-a-bitcoin-node","How to run a Bitcoin Node with Umbrel Home","2025-07-14",[753,754],"node","umbrel",{"url":706,"title":756},"How to run a Bitcoin node",{"path":758,"title":759,"date":760,"tags":761,"category":622,"featureImage":762},"\u002Fposts\u002Fhow-to-get-started-with-nostr","How to get started with Nostr","2024-10-09",[622,626,624,625],{"url":628,"title":759},{"path":530,"title":529,"date":764,"tags":6,"category":494,"featureImage":765},"2024-10-08",{"url":766,"title":529},"v1690313878\u002Fnuxt-header_tbc9cp",{"path":768,"title":769,"date":770,"tags":6,"category":494,"featureImage":771},"\u002Fposts\u002Fhow-to-add-tailwindcss-to-nuxt","How to add tailwindcss to nuxt","2024-10-07",{"url":766,"title":772},"Getting started with Nuxt",{"path":774,"title":772,"date":775,"tags":6,"category":494,"featureImage":776},"\u002Fposts\u002Fgetting-started-with-nuxt","2024-10-06",{"url":766,"title":772},{"path":778,"title":779,"date":775,"tags":6,"category":494,"featureImage":780},"\u002Fposts\u002Fhow-to-store-terraform_state-in-digital-ocean-space","How to store Terraform state in DigitalOcean Spaces",{"url":499,"title":779},{"path":503,"title":5,"date":495,"tags":6,"category":494,"featureImage":782},{"url":499,"title":5},{"path":784,"title":785,"date":786,"tags":6,"category":624,"featureImage":787},"\u002Fposts\u002Fhow-to-add-fathom-analytics-to-nuxt","How to add Fathom Analytics to Nuxt","2024-07-01",{"url":766,"title":785},{"path":789,"title":790,"date":786,"tags":6,"category":624,"featureImage":791},"\u002Fposts\u002Fimportance-of-privacy-in-web-analytics","The Importance of Privacy in Web Analytics",{"url":792,"title":790},"v1690313893\u002Fanalytics_nlew9f",{"path":794,"title":795,"date":786,"tags":796,"category":622,"featureImage":797},"\u002Fposts\u002Fwhat-is-a-nip-07-signer","What is a NIP-07 signer?",[622,667,666,635],{"url":628,"title":795},{"path":799,"title":800,"date":786,"tags":801,"category":622,"featureImage":803},"\u002Fposts\u002Fwhat-is-nostr","What is Nostr?",[622,802,624,651],"relays",{"url":628,"title":800},{"path":805,"title":806,"date":786,"tags":6,"category":624,"featureImage":807},"\u002Fposts\u002Fwhy-choose-privacy-focused-analytics","Why choose privacy focused Analytics",{"url":808,"title":806},"v1690313893\u002Fblog\u002Ffathom-header_y7s0x2",{"path":810,"title":811,"date":812,"tags":6,"category":494,"featureImage":813},"\u002Fposts\u002Fwhat-is-api-integration","What is API Integration?","2024-06-04",{"url":814,"title":815},"v1719908247\u002Fapi_f3f1mh","What is API integration?",{"path":817,"title":818,"date":819,"tags":820,"category":704,"featureImage":822},"\u002Fposts\u002Fhow-blockchain-uses-cryptography","How Blockchain uses Cryptography","2024-05-18",[821,677],"blockchain",{"url":823,"title":824},"v1690313893\u002Fblockchain_tfrcrd","What is blockchain?",{"path":826,"title":827,"date":828,"tags":6,"category":494,"featureImage":829},"\u002Fposts\u002Fhow-to-create-a-websocket-server-in-dotnet","How to create a WebSocket server in dotnet","2024-05-15",{"url":830,"title":827},"v1719908486\u002Fwebsockets_pjqtld",{"path":832,"title":833,"date":828,"tags":834,"category":704,"featureImage":835},"\u002Fposts\u002Fwhat-is-blockchain","What is Blockchain",[821,704],{"url":823,"title":824},{"path":837,"title":838,"date":839,"tags":840,"category":704,"featureImage":842},"\u002Fposts\u002Fintroduction-to-public-and-private-key-cryptography","Public Key Cryptography Explained: A Beginner's Guide","2024-05-12",[841,704,622],"encryption",{"url":823,"title":843},"Introduction to public and private key cryptography",{"path":845,"title":846,"date":839,"tags":847,"category":704,"featureImage":848},"\u002Fposts\u002Fwhat-is-bitcoin","What is Bitcoin?",[821,704],{"url":706,"title":846},{"path":535,"title":534,"date":850,"tags":6,"category":494,"featureImage":851},"2023-09-06",{"url":830,"title":852},"What are Websockets",{"path":854,"title":855,"date":856,"tags":6,"category":494,"featureImage":857},"\u002Fposts\u002Fwhat-is-api-first","What is API First?","2023-07-13",{"url":814,"title":855},{"path":859,"title":860,"date":861,"tags":6,"category":494,"featureImage":862},"\u002Fposts\u002Fapi-gateway-pattern","API Gateway Pattern","2023-06-10",{"url":814,"title":860},{"path":864,"title":865,"date":861,"tags":6,"category":494,"featureImage":866},"\u002Fposts\u002Fbackend-for-frontend-design-pattern","Backend for Frontend Design Pattern",{"url":814,"title":865},{"path":868,"title":869,"date":870,"tags":6,"category":494,"featureImage":871},"\u002Fposts\u002Fguide-api-development","An introductory guide to API Development","2023-06-05",{"url":814,"title":872},"API Development",{"path":874,"title":875,"date":870,"tags":6,"category":494,"featureImage":876},"\u002Fposts\u002Fwhat-is-a-rest-api","What is a REST API?",{"url":814,"title":877},"What is an API?",{"path":879,"title":877,"date":880,"tags":6,"category":494,"featureImage":881},"\u002Fposts\u002Fwhat-is-an-api","2023-06-01",{"url":814,"title":877},{"path":883,"title":884,"date":880,"tags":6,"category":494,"featureImage":885},"\u002Fposts\u002Fwhat-is-api-development","What is API Development ?",{"url":814,"title":886},"What is API development?",[888,889],{"label":559,"description":560,"icon":561,"to":562},{"label":564,"description":565,"icon":566,"to":567},[891,892],{"label":546,"icon":547,"description":548,"to":549},{"label":551,"icon":552,"description":553,"to":554},[894],{"label":572,"icon":573,"description":574,"to":575},[896,899,902,905,908],{"path":897,"title":898},"\u002Flegals\u002Fcookie-policy","Cookie Policy",{"path":900,"title":901},"\u002Flegals\u002Fcopyright","Copyright",{"path":903,"title":904},"\u002Flegals\u002Fcustomer-support","Customer Support",{"path":906,"title":907},"\u002Flegals\u002Fprivacy-policy","Privacy Policy",{"path":909,"title":910},"\u002Flegals\u002Fterms-of-service","Terms of Service",1793132669430]