<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>HowTo &amp;mdash; John Bellone</title>
    <link>https://jbellone.blog/tag:HowTo</link>
    <description>Technology executive. Gamer. &lt;a href=&#34;https://byteswisdom.com&#34;&gt;Podcaster&lt;/a&gt;. &lt;a href=&#34;https://bsky.app/profile/jbellone.dev&#34;&gt;Opinions are mine.&lt;/a&gt;</description>
    <pubDate>Sun, 26 Apr 2026 14:01:15 +0000</pubDate>
    <image>
      <url>https://i.snap.as/Z0MYWOgb.jpg</url>
      <title>HowTo &amp;mdash; John Bellone</title>
      <link>https://jbellone.blog/tag:HowTo</link>
    </image>
    <item>
      <title>Modern Blogging with Ghost</title>
      <link>https://jbellone.blog/modern-blogging-with-ghost?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Over the last 20+ years my personal blogging has been marred with fits and starts. The services/platforms/tools that I have used to host my words are countless – I literally can&#39;t name them all – but I had thought that I found a platform in Mediumwith a balance of style, customization and best of all dead simple tooling. All of that changed about a year ago when, like many other Internet businesses, their model for revenue changed and I was constantly begged to pay money to read other people&#39;s thoughts.&#xA;&#xA;#Technology #Blogging #HowTo&#xA;&#xA;!--more--&#xA;&#xA;Now, I am all for ensuring that content creators are paid, but after having a &#34;taste&#34; of the platform as it was I didn&#39;t really see myself wanting to contribute to it. That led me to take a look at the Ghost platform. This post isn&#39;t really about why I chose Ghost but a major reason was because of how dead simple it is to self-host.&#xA;&#xA;Before we get into the nerdy technical bits it is important to note that rather than self-hosting on Digital Ocean (or some other cloud provider) you can pay a yearly fee to have a managed version with Ghost Pro. It was my decision to not go down that road because I want the flexibility to modify the source code myself. It also happens to be quite a bit cheaper with only minimal risk.&#xA;&#xA;Domain Purchase&#xA;&#xA;There are a countless number of vendors that offer the ability to purchase a domain name. In this example, I have used Google Domains, but you can use any service that fits your needs. In some cases, certain Top Level Domains (TLD) are only offered from specific vendors, e.g. the .dev TLD from Google, which obviously will force your purchase one way or another. But for the common extensions you can use any registrar.&#xA;&#xA;  The domain for this blog was purchased using Google Domains.&#xA;&#xA;Most modern registrars offer an initial configuration for DNS nameservers and a user interface to manage records. We&#39;ll be adding an A record after we set up the Ghost instance in Digital Ocean.&#xA;&#xA;Set Up Ghost with Digital Ocean&#xA;&#xA;  Digital Ocean&#39;s Marketplace offers 1-Click installation of Ghost and many other applications.&#xA;&#xA;Digital Ocean offers an excellent Marketplace that has 1-click installations for many different types of software. The single click creation of a droplet running Ghost is foolproof. This will bring you to the instance creation page that has a whole lot of toggles, but my suggestions for setting up a simple installation of Ghost:&#xA;&#xA;Set the hostname to the domain name you purchased for your blog.&#xA;$10/month instance with 2GB ram and 1 CPU.&#xA;Select a region nearest to your core audience.&#xA;Tag your instance with blog for quick searching.&#xA;Add instance backups for $2/month.&#xA;&#xA;After you click the Create Droplet button and the instance finishes booting you&#39;ll see the public IPV4 address. This is what you&#39;re going to use to configure the A record in your registrar&#39;s domain configuration.&#xA;&#xA;Configure Domain&#xA;&#xA;  The data for the A record is the IPV4 address of the new Digital Ocean instance.&#xA;&#xA;Now that your instance is available the final external step is to configure the DNS A record for the domain. Most people are going to want to add two records:&#xA;&#xA;The @ A record, e.g. https://jbellone.blog/&#xA;The www CNAME record, e.g. https://www.jbellone.blog/&#xA;&#xA;The data component on the A record is the IPV4 address of your Digital Ocean droplet and the data component on the CNAME record would be set to @. But if you&#39;re using Google Domains, you can leverage smart forwarding and forego the second record.&#xA;&#xA;  Google Domains gives you the option of setting up smart forwarding.&#xA;&#xA;The domain forwarding option allows the most flexibility and if your registrar offers it you should definitely take advantage. After the records are set up it is time to follow the Getting Started Guide from the Digital Ocean marketplace. This will walk you through the initial set up of the instance.&#xA;&#xA;Your First Post&#xA;&#xA;If you&#39;ve made it to this point you&#39;re ready to start configuring your Ghost installation. My suggestion would be to walk through the Settings and set up all of the parameters for your blog, e.g. title, description and theme. There are also a whole set of integrations that you can leverage with social accounts such as Twitter to automate the posting.&#xA;&#xA;If you run into any trouble feel free to reach out to me on Bluesky_or send me an e-mail.]]&gt;</description>
      <content:encoded><![CDATA[<p>Over the last 20+ years my personal blogging has been marred with fits and starts. The services/platforms/tools that I have used to host my words are countless – I literally can&#39;t name them all – but I had thought that I found a platform in <a href="https://medium.com/">Medium</a>with a balance of style, customization and best of all dead simple tooling. All of that changed about a year ago when, like many other Internet businesses, their model for revenue changed and I was constantly begged to pay money to read other people&#39;s thoughts.</p>

<p><a href="https://jbellone.blog/tag:Technology" class="hashtag"><span>#</span><span class="p-category">Technology</span></a> <a href="https://jbellone.blog/tag:Blogging" class="hashtag"><span>#</span><span class="p-category">Blogging</span></a> <a href="https://jbellone.blog/tag:HowTo" class="hashtag"><span>#</span><span class="p-category">HowTo</span></a></p>



<p>Now, I am all for ensuring that content creators are paid, but after having a “taste” of the platform as it was I didn&#39;t really see myself wanting to contribute to it. That led me to take a look at the <a href="https://ghost.org/">Ghost</a> platform. This post isn&#39;t really about <em>why</em> I chose Ghost but a major reason was because of how dead simple it is to self-host.</p>

<p>Before we get into the nerdy technical bits it is important to note that rather than self-hosting on Digital Ocean (or some other cloud provider) you can pay a yearly fee to have a managed version with <a href="https://ghost.org/pricing/">Ghost Pro</a>. It was my decision to not go down that road because I want the flexibility to modify the <a href="https://github.com/johnbellone/TryGhost">source code</a> myself. It also happens to be quite a bit cheaper with only minimal risk.</p>

<h3 id="domain-purchase" id="domain-purchase">Domain Purchase</h3>

<p>There are a countless number of vendors that offer the ability to purchase a domain name. In this example, I have used <a href="https://domains.google/">Google Domains</a>, but you can use any service that fits your needs. In some cases, certain <a href="https://en.wikipedia.org/wiki/Top-level_domain">Top Level Domains (TLD)</a> are only offered from specific vendors, e.g. the <strong>.dev</strong> TLD from Google, which obviously will force your purchase one way or another. But for the common extensions you can use any registrar.</p>

<blockquote><p><img src="https://i.snap.as/9XbPCbqn.png" alt=""/> The domain for this blog was purchased using <strong><a href="https://domains.google/">Google Domains</a></strong>.</p></blockquote>

<p>Most modern registrars offer an initial configuration for DNS nameservers and a user interface to manage records. We&#39;ll be adding an <a href="https://en.wikipedia.org/wiki/List_of_DNS_record_types">A record</a> after we set up the Ghost instance in Digital Ocean.</p>

<h3 id="set-up-ghost-with-digital-ocean" id="set-up-ghost-with-digital-ocean">Set Up Ghost with Digital Ocean</h3>

<blockquote><p><img src="https://i.snap.as/j569s2VM.png" alt=""/> <a href="https://marketplace.digitalocean.com/">Digital Ocean&#39;s Marketplace</a> offers <a href="https://marketplace.digitalocean.com/apps/ghost">1-Click installation of Ghost</a> and many other applications.</p></blockquote>

<p><a href="https://m.do.co/c/e547caed128e">Digital Ocean</a> offers an excellent <a href="https://marketplace.digitalocean.com/">Marketplace</a> that has 1-click installations for many different types of software. The s<a href="https://marketplace.digitalocean.com/apps/ghost">ingle click creation of a droplet</a> running Ghost is foolproof. This will bring you to the instance creation page that has a whole lot of toggles, but my suggestions for setting up a simple installation of Ghost:</p>
<ul><li>Set the <em>hostname</em> to the <em>domain name</em> you purchased for your blog.</li>
<li>$10/month instance with 2GB ram and 1 CPU.</li>
<li>Select a region nearest to your core audience.</li>
<li>Tag your instance with <em>blog</em> for quick searching.</li>
<li>Add instance backups for $2/month.</li></ul>

<p>After you click the <em>Create Droplet button</em> and the instance finishes booting you&#39;ll see the public IPV4 address. This is what you&#39;re going to use to configure the A record in your registrar&#39;s domain configuration.</p>

<h3 id="configure-domain" id="configure-domain">Configure Domain</h3>

<blockquote><p><img src="https://i.snap.as/Twa7xs5P.png" alt=""/> The data for the <a href="https://en.wikipedia.org/wiki/List_of_DNS_record_types">A record</a> is the IPV4 address of the new Digital Ocean instance.</p></blockquote>

<p>Now that your instance is available the final external step is to configure the DNS A record for the domain. Most people are going to want to add two records:</p>
<ul><li>The @ A record, e.g. <a href="https://jbellone.blog/">https://jbellone.blog/</a></li>
<li>The <em>www</em> CNAME record, e.g. <a href="https://www.jbellone.blog/">https://www.jbellone.blog/</a></li></ul>

<p>The data component on the A record is the IPV4 address of your Digital Ocean droplet and the data component on the CNAME record would be set to @. But if you&#39;re using Google Domains, you can leverage smart forwarding and forego the second record.</p>

<blockquote><p><img src="https://i.snap.as/ejuvKtLb.png" alt=""/> Google Domains gives you the option of setting up smart forwarding.</p></blockquote>

<p>The domain forwarding option allows the most flexibility and if your registrar offers it you should definitely take advantage. After the records are set up it is time to follow the <a href="https://cloud.digitalocean.com/marketplace/5ba19753fc53b8179c7a0076?i=9e0881">Getting Started Guide</a> from the Digital Ocean marketplace. This will walk you through the initial set up of the instance.</p>

<h3 id="your-first-post" id="your-first-post">Your First Post</h3>

<p>If you&#39;ve made it to this point you&#39;re ready to start configuring your Ghost installation. My suggestion would be to walk through the <em>Settings</em> and set up all of the parameters for your blog, e.g. title, description and theme. There are also a whole set of integrations that you can leverage with social accounts such as Twitter to automate the posting.</p>

<p>If you run into any trouble feel free to reach out to me on <em><a href="https://bsky.app/profile/jbellone.dev">Bluesky</a></em>or <a href="mailto:me@jbellone.blog">send me an e-mail</a>.</p>
]]></content:encoded>
      <guid>https://jbellone.blog/modern-blogging-with-ghost</guid>
      <pubDate>Fri, 28 Aug 2020 01:57:07 +0000</pubDate>
    </item>
    <item>
      <title>Hydration of a Chef Server</title>
      <link>https://jbellone.blog/hydration-of-a-chef-server?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[At Bloomberg my team is tasked with supporting infrastructure for all of our consumer and subscription web properties. We have been using Chef to solve some of our problems around configuration management. Most of our recipes were built using Chef Solo and eventually deployed on our cloud infrastructure without a Chef Server. As we began to plan to deploy software services to the teams that we support we quickly began to realize that it would be nearly impossible to manage multiple node deployments without Chef Server.&#xA;&#xA;#Technology #HowTo #DevOps&#xA;&#xA;!--more--&#xA;&#xA;Requirements&#xA;&#xA;Our immediate need was to provision a Chef Server for our build infrastructure that we would be distributing to about twenty teams. But in addition to this we have brought in Chef to train several classes of our developers. After the classes concluded there were many requests for individual Chef Server tenancies for testing.&#xA;&#xA;Using Chef Server within our infrastructure was an afterthought because most of our virtual machines had a very short lifespan. Since we could have several dozen development teams wanting their own Chef Server deployments we needed a solution to not only easily deploy a Chef Server, but to hydrate it with the data necessary for each OpenStack tenancy. This included both user and client authentication information.&#xA;&#xA;After a bit of back and forth I was able to isolate the requirements for our Chef Server infrastructure:&#xA;&#xA;It must use the Chef Server community cookbook and the Omnibus packages provided by Chef;&#xA;&#xA;It should be quick and easy to deploy a new instance because we may be doing so for several dozen tenancies in OpenStack;&#xA;&#xA;All user and client keys should be generated locally and the server should be hydrated during the initial convergence run;&#xA;&#xA;Playing With Metal&#xA;&#xA;I was first introduced to Chef Metal at this past year’s ChefConf where John Keiser gave an excellent talk. My team has a lot of experience using Vagrant, but it made much more sense to me to include a metal recipe with our Chef infrastructure cookbook. It could serve as both a teaching aide, and would also make our internal cookbooks much more versatile. Throughout the discovery process I found the community Chef Server Populator cookbook, ended up completely rewriting it to use Chef resources to modify the Chef Server, and ultimately used Chef Zero to bootstrap everything.&#xA;&#xA;Using Chef Metal I was able to easily distribute a recipe with our Chef infrastructure cookbook that would provision a Chef Server very easily using the machine resource. The recipe that I began with looked very similar to what is below. It first laid down changes to the base operating system using our base cookbook, and simply used the community cookbook to install the Chef Server from the Omnibus packages. It was very straight forward.&#xA;&#xA;Unfortunately I still needed to hydrate the local data into the newly minted Chef Server. Luckily for me the cats over at Heavy Water Operations have solved this problem and provided the Chef Server Populator cookbook. There were only a few minor modifications that I needed to make to support client validation keys. But other than that everything seemed to be smooth sailing.&#xA;&#xA;Chef Zero&#xA;&#xA;At first, with only a few minor changes, the Chef Server Populator cookbook seemed to be the answer to my problems. I had a few cases that were not covered, but these were all pretty simple extensions. It was natural and made sense to convert our Chef infrastructure cookbook into a Chef repository and use Chef Zero as an in-memory Chef Server during the initial provisioning.&#xA;&#xA;That worked out quite well at first. I was able to cobble together a simple Rake task to generate and write out the private and public keys to JSON data bag items. My metal recipe started to look a lot more complex than I had initially intended, and it didn’t seem as clean as I thought it could be. As I was reading through the code for the Chef Metal Fog driver a light bulb went off in my head: I could use the Cheffish gem Chef resources and build the data on the fly!&#xA;&#xA;Chef within Chef&#xA;&#xA;I ended up completely rewriting the Chef Server Populator cookbook. My fork now used the Chef resources provided by the Cheffish gem to read from data bag items and create the user and client records against the Chef Server node. The beauty of this approach is that I no longer had to execute clunky knife commands since in Chef 11 erchef exposed an API to pass both user and client public keys. The cookbook is now much more clean and simple to grok.&#xA;&#xA;The code for creating the user and client keys was also able to use the same Chef resources from Cheffish. Instead of operating against our newly provisioned Chef Server it executed against the in-memory server provided by Chef Zero.&#xA;&#xA;Using keys which are generated inside of the metal recipe is not idempotent. There were two ways that I went about solving this problem. This first was merely reading in the private keys off disk and delegating the generation to some external process. The second would be to use the Chef resource to generate private keys and allow it to manage if they needed to be updated or not. Ultimately it worked out that if the keys were generated outside of the metal recipe it was much more straightforward. Here is a full example where keys for clients were generated outside, but user keys are generated on the fly:&#xA;&#xA;https://gist.github.com/johnbellone/5a72111898c7709dddeb&#xA;&#xA;Tying The Bow&#xA;&#xA;The final result was a complete cookbook refactor which uses Chef resources to hydrate a newly provisioned Chef Server. The default recipe uses node attributes and creates both client and user resources on the new server. A data bag recipe uses a Chef data bag search to find items and applies them to the node attributes prior to including the default recipe.&#xA;&#xA;Since Chef Zero provides a fully functioning in-memory Chef Server we are able to use Chef resources to add data bag items with locally generated public keys. When using the Chef Metal recipe this data is now made accessible to the data bag search, and thus it gives us an elegant way to hydrate a Chef Server. I have provided an example of this inside of my fork of the cookbook which illustrates all of the steps above.&#xA;&#xA;As I mentioned at the top of this post I originally started work on this solution to allow us to quickly deploy our build infrastructure to multiple tenancies within our private cloud. In a future post I will explain how my team was able to create an easily deployable continuous integration framework using the community Jenkins recipe.&#xA;&#xA;If you are reading this post and are interested in joining our growing group of Chef technologists at Bloomberg feel free to reach out to me. We are hiring!]]&gt;</description>
      <content:encoded><![CDATA[<p>At <a href="http://jobs.bloomberg.com/search/?q=chef">Bloomberg</a> my team is tasked with supporting infrastructure for all of our consumer and subscription web properties. We have been using Chef to solve some of our problems around configuration management. Most of our recipes were built using Chef Solo and eventually deployed on our cloud infrastructure without a Chef Server. As we began to plan to deploy software services to the teams that we support we quickly began to realize that it would be nearly impossible to manage multiple node deployments without Chef Server.</p>

<p><a href="https://jbellone.blog/tag:Technology" class="hashtag"><span>#</span><span class="p-category">Technology</span></a> <a href="https://jbellone.blog/tag:HowTo" class="hashtag"><span>#</span><span class="p-category">HowTo</span></a> <a href="https://jbellone.blog/tag:DevOps" class="hashtag"><span>#</span><span class="p-category">DevOps</span></a></p>



<h3 id="requirements" id="requirements">Requirements</h3>

<p>Our immediate need was to provision a Chef Server for our build infrastructure that we would be distributing to about twenty teams. But in addition to this we have brought in <a href="https://getchef.com/">Chef</a> to train several classes of our developers. After the classes concluded there were many requests for individual Chef Server tenancies for testing.</p>

<p>Using Chef Server within our infrastructure was an afterthought because most of our virtual machines had a very short lifespan. Since we could have several dozen development teams wanting their own Chef Server deployments we needed a solution to not only easily deploy a Chef Server, but to hydrate it with the data necessary for each OpenStack tenancy. This included both user and client authentication information.</p>

<p>After a bit of back and forth I was able to isolate the requirements for our Chef Server infrastructure:</p>
<ol><li><p>It must use the <a href="https://github.com/opscode-cookbooks/chef-server">Chef Server community cookbook</a> and the <a href="https://github.com/opscode/omnibus-chef-server">Omnibus packages provided by Chef</a>;</p></li>

<li><p>It should be quick and easy to deploy a new instance because we may be doing so for several dozen tenancies in OpenStack;</p></li>

<li><p>All user and client keys should be generated locally and the server should be hydrated during the initial convergence run;</p></li></ol>

<h3 id="playing-with-metal" id="playing-with-metal">Playing With Metal</h3>

<p>I was first introduced to <a href="https://github.com/opscode/chef-metal">Chef Metal</a> at this past year’s ChefConf where <a href="http://slides.com/jkeiser/chef-metal">John Keiser gave an excellent talk</a>. My team has a lot of experience using Vagrant, but it made much more sense to me to include a metal recipe with our Chef infrastructure cookbook. It could serve as both a teaching aide, and would also make our internal cookbooks much more versatile. Throughout the discovery process I found the community <a href="https://github.com/hw-cookbooks/chef-server-populator">Chef Server Populator cookbook</a>, ended up completely rewriting it to use Chef resources to modify the Chef Server, and ultimately used Chef Zero to bootstrap everything.</p>

<p>Using Chef Metal I was able to easily distribute a recipe with our Chef infrastructure cookbook that would provision a Chef Server very easily using the <em>machine resource.</em> The recipe that I began with looked very similar to what is below. It first laid down changes to the base operating system using our base cookbook, and simply used the community cookbook to install the Chef Server from the Omnibus packages. It was very straight forward.</p>

<p>Unfortunately I still needed to hydrate the local data into the newly minted Chef Server. Luckily for me the cats over at <a href="http://hw-ops.com/">Heavy Water Operations</a> have solved this problem and provided the <a href="https://github.com/hw-cookbooks/chef-server-populator">Chef Server Populator cookbook</a>. There were only a few minor modifications that I needed to make to support client validation keys. But other than that everything seemed to be smooth sailing.</p>

<h4 id="chef-zero" id="chef-zero">Chef Zero</h4>

<p>At first, with only a few minor changes, the Chef Server Populator cookbook seemed to be the answer to my problems. I had a few cases that were not covered, but these were all pretty simple extensions. It was natural and made sense to convert our Chef infrastructure cookbook into a Chef repository and use <a href="https://github.com/opscode/chef-zero">Chef Zero</a> as an in-memory Chef Server during the initial provisioning.</p>

<p>That worked out quite well at first. I was able to cobble together a simple Rake task to generate and write out the private and public keys to JSON data bag items. My metal recipe started to look a lot more complex than I had initially intended, and it didn’t seem as clean as I thought it could be. As I was reading through the code for the <a href="https://github.com/opscode/chef-metal-fog">Chef Metal Fog driver</a> a light bulb went off in my head: I could use the <a href="https://github.com/opscode/cheffish">Cheffish gem</a> Chef resources and build the data on the fly!</p>

<h4 id="chef-within-chef" id="chef-within-chef">Chef within Chef</h4>

<p>I ended up completely rewriting the Chef Server Populator cookbook. <a href="https://github.com/johnbellone/chef-server-populator">My fork</a> now used the Chef resources provided by the Cheffish gem to read from data bag items and create the user and client records against the Chef Server node. The beauty of this approach is that I no longer had to execute clunky knife commands since in Chef 11 erchef exposed an API to pass both user and client public keys. The cookbook is <a href="https://github.com/johnbellone/chef-server-populator">now much more clean and simple to grok</a>.</p>

<p>The code for creating the user and client keys was also able to use the same Chef resources from Cheffish. Instead of operating against our newly provisioned Chef Server it executed against the in-memory server provided by Chef Zero.</p>

<p>Using keys which are generated inside of the metal recipe is not idempotent. There were two ways that I went about solving this problem. This first was merely reading in the private keys off disk and delegating the generation to some external process. The second would be to use the Chef resource to generate private keys and allow it to manage if they needed to be updated or not. Ultimately it worked out that if the keys were generated outside of the metal recipe it was much more straightforward. Here is a full example where keys for clients were generated outside, but user keys are generated on the fly:</p>

<p><script src="https://gist.github.com/johnbellone/5a72111898c7709dddeb.js"></script></p>

<h4 id="tying-the-bow" id="tying-the-bow">Tying The Bow</h4>

<p>The final result was a complete <a href="https://github.com/johnbellone/chef-server-populator">cookbook refactor</a> which uses Chef resources to hydrate a newly provisioned Chef Server. The default recipe uses node attributes and creates both client and user resources on the new server. A data bag recipe uses a Chef data bag search to find items and applies them to the node attributes prior to including the default recipe.</p>

<p>Since Chef Zero provides a fully functioning in-memory Chef Server we are able to use Chef resources to add data bag items with locally generated public keys. When using the Chef Metal recipe this data is now made accessible to the data bag search, and thus it gives us an elegant way to hydrate a Chef Server. I have provided an example of this <a href="https://github.com/johnbellone/chef-server-populator/blob/master/examples/chef-server.rb">inside of my fork of the cookbook</a> which illustrates all of the steps above.</p>

<p>As I mentioned at the top of this post I originally started work on this solution to allow us to quickly deploy our build infrastructure to multiple tenancies within our private cloud. In a future post I will explain how my team was able to create an easily deployable continuous integration framework using the <a href="https://github.com/opscode-cookbooks/jenkins">community Jenkins recipe</a>.</p>

<p>If you are reading this post and are interested in joining our growing group of Chef technologists at Bloomberg feel free to reach out to me. <a href="http://jobs.bloomberg.com/search/?q=chef">We are hiring</a>!</p>
]]></content:encoded>
      <guid>https://jbellone.blog/hydration-of-a-chef-server</guid>
      <pubDate>Sat, 18 Oct 2014 00:24:05 +0000</pubDate>
    </item>
  </channel>
</rss>