<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.juliotrigo.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.juliotrigo.com/" rel="alternate" type="text/html" hreflang="en-GB" /><updated>2026-01-01T17:39:59+00:00</updated><id>https://www.juliotrigo.com/feed.xml</id><title type="html">Julio Trigo</title><subtitle>[&quot;Software engineer&quot;, &quot;Scrum master (CSM)&quot;, &quot;Python developer&quot;, &quot;Team lead&quot;, &quot;Dev lead&quot;]
</subtitle><author><name>Julio Trigo</name></author><entry><title type="html">Installing Node.js and npm on a Mac</title><link href="https://www.juliotrigo.com/articles/installing-nodejs-and-npm-on-a-mac/" rel="alternate" type="text/html" title="Installing Node.js and npm on a Mac" /><published>2024-01-27T11:15:00+00:00</published><updated>2025-11-29T21:45:00+00:00</updated><id>https://www.juliotrigo.com/articles/installing-nodejs-and-npm-with-nvm-on-a-mac</id><content type="html" xml:base="https://www.juliotrigo.com/articles/installing-nodejs-and-npm-on-a-mac/"><![CDATA[<p>Recently, I installed Node.js and npm on my Mac and thought of documenting the steps I followed
for future reference, which will be helpful the next time I have to do it.</p>

<!--more-->

<h2 id="choosing-the-nodejs-version-manager">Choosing the Node.js version manager</h2>

<p>As we can read in the installation and setup documentation for <code class="language-plaintext highlighter-rouge">npm</code>
(<a href="https://npm.github.io/installation-setup-docs/installing/using-a-node-version-manager.html">Using a Node Version Manager</a>):</p>

<blockquote>
  <p>There are a lot of different versions of Node out there.
These tools will help you keep track of what version you are using, and also make it easy to
install new versions and switch between them. They also make npm easier to set up :)</p>
</blockquote>

<p>I decided to go with NVM (Node Version Manager), which seems to be widely adopted and it’s also the
one I was familiar with.</p>

<h2 id="nvm-installation">nvm installation</h2>

<p>First of all we need to install <code class="language-plaintext highlighter-rouge">nvm</code> in our system by following the instructions on its
GitHub <a href="https://github.com/nvm-sh/nvm#installing-and-updating">README</a> page.</p>

<p>I usually prefer to go with a manual installation in order to be more in control of how things are
set up. The <a href="https://github.com/nvm-sh/nvm#git-install">Git Install</a> option fits this approach:</p>

<ul>
  <li>Clone the repository and checkout the latest version:</li>
</ul>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cd</span> ~/
<span class="nv">$ </span>git clone https://github.com/nvm-sh/nvm.git .nvm
<span class="nv">$ </span><span class="nb">cd</span> ~/.nvm
<span class="nv">$ </span>git checkout v0.39.7
</code></pre></div></div>

<ul>
  <li>Activate <code class="language-plaintext highlighter-rouge">nvm</code> by sourcing it from the shell:</li>
</ul>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">.</span> ./nvm.sh
</code></pre></div></div>

<ul>
  <li>Add these lines to the <code class="language-plaintext highlighter-rouge">~/.zshrc</code> file to have it automatically sourced in interactive shells:</li>
</ul>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">NVM_DIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.nvm"</span>
<span class="o">[</span> <span class="nt">-s</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/nvm.sh"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\.</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/nvm.sh"</span>  <span class="c"># This loads nvm</span>
<span class="o">[</span> <span class="nt">-s</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/bash_completion"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\.</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/bash_completion"</span>  <span class="c"># This loads nvm bash_completion</span>
</code></pre></div></div>

<p><strong>Note</strong>: it assumes we’re using <code class="language-plaintext highlighter-rouge">zsh</code>.</p>

<ul>
  <li>Verify installation:</li>
</ul>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nvm <span class="nt">--version</span>
0.39.7
</code></pre></div></div>

<h2 id="node--npm-installation">node / npm installation</h2>

<p>Check that we don’t currently have any versions of Node.js installed:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nvm current
none
</code></pre></div></div>

<p>Now we can install different versions of Node.js / <code class="language-plaintext highlighter-rouge">npm</code> with <code class="language-plaintext highlighter-rouge">nvm</code>:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nvm <span class="nb">install </span>16.13.0
Downloading and installing node v16.13.0...
Downloading https://nodejs.org/dist/v16.13.0/node-v16.13.0-darwin-x64.tar.xz...
<span class="c">################################################################################################################################ 100.0%</span>
Computing checksum with shasum <span class="nt">-a</span> 256
Checksums matched!
Now using node v16.13.0 <span class="o">(</span>npm v8.1.0<span class="o">)</span>
Creating default <span class="nb">alias</span>: default -&gt; 16.13.0 <span class="o">(</span>-&gt; v16.13.0<span class="o">)</span>
</code></pre></div></div>

<p>Alternatively, we can install the latest LTS version directly:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nvm <span class="nb">install</span> <span class="nt">--lts</span>
</code></pre></div></div>

<h3 id="verify-versions">Verify versions</h3>

<p>And then we can verify the versions of <code class="language-plaintext highlighter-rouge">node</code> and <code class="language-plaintext highlighter-rouge">npm</code> that are currently active:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nvm current
v16.13.0

<span class="nv">$ </span>node <span class="nt">--version</span>
v16.13.0

<span class="nv">$ </span>npm <span class="nt">--version</span>
8.1.0
</code></pre></div></div>

<h3 id="npm-version">npm version</h3>

<p>When installing Node.js, each version of <code class="language-plaintext highlighter-rouge">node</code> is bundled with a version of <code class="language-plaintext highlighter-rouge">npm</code>:</p>
<ul>
  <li><a href="https://nodejs.org/en/download/releases/">Previous Releases / Node.js</a></li>
  <li><a href="https://nodejs.org/dist/index.json">Node.js distributions</a></li>
</ul>

<h2 id="nvm-usage">nvm usage</h2>

<h3 id="list-node-versions">List node versions</h3>

<p>We can list all the Node.js versions we’ve got installed:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nvm <span class="nb">ls</span>
-&gt;     v16.13.0
default -&gt; 16.13.0 <span class="o">(</span>-&gt; v16.13.0<span class="o">)</span>
node -&gt; stable <span class="o">(</span>-&gt; v16.13.0<span class="o">)</span> <span class="o">(</span>default<span class="o">)</span>
stable -&gt; 16.13 <span class="o">(</span>-&gt; v16.13.0<span class="o">)</span> <span class="o">(</span>default<span class="o">)</span>
</code></pre></div></div>

<p>And all the available versions out there:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nvm ls-remote
</code></pre></div></div>

<h3 id="switch-between-node-versions">Switch between node versions</h3>

<p>If we had multiple versions of Node.js installed then we could switch between them:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nvm use 16.13.0
Now using node v16.13.0 <span class="o">(</span>npm v8.1.0<span class="o">)</span>

<span class="c"># Use the Node.js version set as `default`</span>
<span class="nv">$ </span>nvm use default
</code></pre></div></div>

<h2 id="nvmrc">.nvmrc</h2>

<p>As explained in the <a href="https://github.com/nvm-sh/nvm#nvmrc">nvm documentation</a>, we can create a
<code class="language-plaintext highlighter-rouge">.nvmrc</code> file containing a Node.js version number in the project directory (or any parent
directory). Afterwards, commands like <code class="language-plaintext highlighter-rouge">nvm use</code>, <code class="language-plaintext highlighter-rouge">nvm install</code>, or <code class="language-plaintext highlighter-rouge">nvm exec</code> will use the version
specified in the <code class="language-plaintext highlighter-rouge">.nvmrc</code> file when no version is explicitly provided.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cd</span> /full/path/to/my_project

<span class="nv">$ </span><span class="nb">cat</span> .nvmrc
17.8.0

<span class="nv">$ </span>nvm use
Found <span class="s1">'/full/path/to/my_project/.nvmrc'</span> with version &lt;17.8.0&gt;
Now using node v17.8.0 <span class="o">(</span>npm v8.5.5<span class="o">)</span>
</code></pre></div></div>

<h2 id="upgrading-nvm">Upgrading nvm</h2>

<p>Since we’ve just cloned the <code class="language-plaintext highlighter-rouge">nvm</code> repository, we can just fetch and check out the latest release in
order to upgrade it. See the <a href="https://github.com/nvm-sh/nvm#manual-upgrade">Manual Upgrade</a> notes.</p>

<p><strong><em>2025-11-29 - Update:</em></strong></p>

<ul>
  <li>Add a note about how to install the latest LTS version</li>
  <li>How to use the <code class="language-plaintext highlighter-rouge">default</code> Node.js version</li>
  <li>Clarified ambiguity with <code class="language-plaintext highlighter-rouge">.nvmrc</code></li>
  <li>Improvements and fixes</li>
</ul>]]></content><author><name>Julio Trigo</name></author><category term="Node.js" /><category term="node" /><category term="npm" /><category term="nvm" /><category term="mac" /><category term="zsh" /><category term="nvmrc" /><summary type="html"><![CDATA[Recently, I installed Node.js and npm on my Mac and thought of documenting the steps I followed for future reference, which will be helpful the next time I have to do it.]]></summary></entry><entry><title type="html">Installing Ruby on a Mac</title><link href="https://www.juliotrigo.com/articles/installing-ruby-on-a-mac/" rel="alternate" type="text/html" title="Installing Ruby on a Mac" /><published>2023-02-28T19:45:00+00:00</published><updated>2025-12-02T19:30:00+00:00</updated><id>https://www.juliotrigo.com/articles/installing-ruby-on-a-mac</id><content type="html" xml:base="https://www.juliotrigo.com/articles/installing-ruby-on-a-mac/"><![CDATA[<p>There are already quite a few guides and articles that explain how to install Ruby, so I don’t
intend to write just another one.</p>

<p>Instead, I’m going to document the steps I followed to install Ruby on my Mac, describe the approach
I chose, and summarise the commands I used. These notes are meant to serve as my personal technical
reference and to help clarify how the Ruby installation process works.</p>

<!--more-->

<h2 id="bibliography">Bibliography</h2>

<p>This is a fantastic article about <a href="https://www.moncefbelyamani.com/how-to-install-xcode-homebrew-git-rvm-ruby-on-mac/">the fastest and easiest way to install Ruby on a Mac</a>, linked from the <a href="https://jekyllrb.com/docs/installation/macos/">Jekyll on macOS</a> installation page.</p>

<p>This is another article that explains the benefits of using <code class="language-plaintext highlighter-rouge">chruby</code>: <a href="https://stevemarshall.com/journal/why-i-use-chruby/">why I use chruby instead of RVM or rbenv</a>.</p>

<p>The <a href="https://www.moncefbelyamani.com/why-you-should-never-use-sudo-to-install-ruby-gems/">Why You Should Never Use sudo to Install Ruby Gems</a> article is also worth reading.</p>

<p>And an article about configuring Bundler to <a href="https://guilhermesimoes.github.io/blog/installing-gems-per-project-directory">install gems in the project directory</a>.</p>

<h2 id="install-chruby-and-ruby-install">Install chruby and ruby-install</h2>

<p>I’m going to use <a href="https://github.com/postmodern/chruby"><code class="language-plaintext highlighter-rouge">chruby</code></a> as a Ruby version manager and <a href="https://github.com/postmodern/ruby-install"><code class="language-plaintext highlighter-rouge">ruby-install</code></a> as a tool to install Ruby.</p>

<p>They can both be installed using <a href="https://brew.sh/">Homebrew</a>.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>brew <span class="nb">install </span>chruby ruby-install
</code></pre></div></div>

<h2 id="install-ruby-versions">Install Ruby versions</h2>

<p>Then we can install all the Ruby versions that we need with <code class="language-plaintext highlighter-rouge">ruby-install</code>:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ruby-install 3.4.7
<span class="o">&gt;&gt;&gt;</span> Installing ruby 3.4.7 into /Users/&lt;username&gt;/.rubies/ruby-3.4.7 ...
<span class="o">&gt;&gt;&gt;</span> Installing dependencies <span class="k">for </span>ruby 3.4.7 ...
<span class="o">&gt;&gt;&gt;</span> Downloading https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.7.tar.xz into /Users/&lt;username&gt;/
<span class="o">&gt;&gt;&gt;</span> Verifying ruby-3.4.7.tar.xz ...
<span class="o">&gt;&gt;&gt;</span> Extracting ruby-3.4.7.tar.xz to /Users/&lt;username&gt;/src/ruby-3.4.7 ...
<span class="o">&gt;&gt;&gt;</span> Configuring ruby 3.4.7 ...
<span class="o">&gt;&gt;&gt;</span> Cleaning ruby 3.4.7 ...
<span class="o">&gt;&gt;&gt;</span> Compiling ruby 3.4.7 ...
<span class="o">&gt;&gt;&gt;</span> Installing ruby 3.4.7 ...
installing bundled gems:            /Users/&lt;username&gt;/.rubies/ruby-3.4.7/lib/ruby/gems/3.4.0
<span class="o">&gt;&gt;&gt;</span> Successfully installed ruby 3.4.7 into /Users/&lt;username&gt;/.rubies/ruby-3.4.7

<span class="nv">$ </span>ruby-install 3.4.5
<span class="o">&gt;&gt;&gt;</span> Installing ruby 3.4.5 into /Users/&lt;username&gt;/.rubies/ruby-3.4.5 ...
<span class="o">&gt;&gt;&gt;</span> Installing dependencies <span class="k">for </span>ruby 3.4.5 ...
<span class="o">&gt;&gt;&gt;</span> Downloading https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.5.tar.xz into /Users/&lt;username&gt;/src ...
<span class="o">&gt;&gt;&gt;</span> Verifying ruby-3.4.5.tar.xz ...
<span class="o">&gt;&gt;&gt;</span> Extracting ruby-3.4.5.tar.xz to /Users/&lt;username&gt;/src/ruby-3.4.5 ...
<span class="o">&gt;&gt;&gt;</span> Configuring ruby 3.4.5 ...
<span class="o">&gt;&gt;&gt;</span> Cleaning ruby 3.4.5 ...
<span class="o">&gt;&gt;&gt;</span> Compiling ruby 3.4.5 ...
<span class="o">&gt;&gt;&gt;</span> Installing ruby 3.4.5 ...
installing bundled gems:            /Users/&lt;username&gt;/.rubies/ruby-3.4.5/lib/ruby/gems/3.4.0
<span class="o">&gt;&gt;&gt;</span> Successfully installed ruby 3.4.5 into /Users/&lt;username&gt;/.rubies/ruby-3.4.5

<span class="nv">$ </span>ruby-install 3.3.6
<span class="o">&gt;&gt;&gt;</span> Installing ruby 3.3.6 into /Users/&lt;username&gt;/.rubies/ruby-3.3.6 ...
<span class="o">&gt;&gt;&gt;</span> Installing dependencies <span class="k">for </span>ruby 3.3.6 ...
<span class="o">&gt;&gt;&gt;</span> Downloading https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.6.tar.xz into /Users/&lt;username&gt;/src ...
<span class="o">&gt;&gt;&gt;</span> Verifying ruby-3.3.6.tar.xz ...
<span class="o">&gt;&gt;&gt;</span> Extracting ruby-3.3.6.tar.xz to /Users/&lt;username&gt;/src/ruby-3.3.6 ...
<span class="o">&gt;&gt;&gt;</span> Configuring ruby 3.3.6 ...
<span class="o">&gt;&gt;&gt;</span> Cleaning ruby 3.3.6 ...
<span class="o">&gt;&gt;&gt;</span> Compiling ruby 3.3.6 ...
<span class="o">&gt;&gt;&gt;</span> Installing ruby 3.3.6 ...
installing bundled gems:            /Users/&lt;username&gt;/.rubies/ruby-3.3.6/lib/ruby/gems/3.3.0
<span class="o">&gt;&gt;&gt;</span> Successfully installed ruby 3.3.6 into /Users/&lt;username&gt;/.rubies/ruby-3.3.6
</code></pre></div></div>

<p>Ruby versions are installed in the <code class="language-plaintext highlighter-rouge">~/.rubies/</code> folder by default:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">ls</span> ~/.rubies
ruby-3.3.6 ruby-3.4.5 ruby-3.4.7
</code></pre></div></div>

<p>Note that the installation output shows gems being installed in paths like
<code class="language-plaintext highlighter-rouge">~/.rubies/ruby-3.4.7/lib/ruby/gems/3.4.0/</code> — these are gems bundled with Ruby
that ship with the installation. See <a href="#installation-location">Installation location</a>
for details on how gem paths work.</p>

<h3 id="compiling-older-ruby-versions">Compiling older Ruby versions</h3>

<p>On some macOS systems, compiling Ruby <code class="language-plaintext highlighter-rouge">3.3.x</code> may fail with:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>error: use of undeclared identifier 'RUBY_FUNCTION_NAME_STRING'
</code></pre></div></div>

<p>This happens when Ruby’s autoconf script fails to detect <code class="language-plaintext highlighter-rouge">__func__</code> support.
To fix this, pass the variable explicitly:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ruby-install 3.3.6 <span class="nt">--</span> <span class="nv">rb_cv_function_name_string</span><span class="o">=</span>__func__
</code></pre></div></div>

<p>See <a href="https://dev.to/franklinyu/error-of-rubyfunctionnamestring-when-compiling-ruby-32b8">this article</a>
for more details.</p>

<h2 id="configure-chruby-in-the-shell">Configure chruby in the shell</h2>

<p>The next step is to configure <code class="language-plaintext highlighter-rouge">chruby</code> in the shell (it assumes we’re using <code class="language-plaintext highlighter-rouge">zsh</code>):</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Load and enable chruby</span>
<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"source </span><span class="si">$(</span>brew <span class="nt">--prefix</span><span class="si">)</span><span class="s2">/opt/chruby/share/chruby/chruby.sh"</span> <span class="o">&gt;&gt;</span> ~/.zshrc

<span class="c"># Enable auto-switching of Rubies specified by .ruby-version files</span>
<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"source </span><span class="si">$(</span>brew <span class="nt">--prefix</span><span class="si">)</span><span class="s2">/opt/chruby/share/chruby/auto.sh"</span> <span class="o">&gt;&gt;</span> ~/.zshrc

<span class="c"># Set the default Ruby version, which should have previously been installed</span>
<span class="c"># Without this, we’d need to manually call `chruby` every time we want to use</span>
<span class="c"># something different than the system Ruby</span>
<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"chruby ruby-3.4.7"</span> <span class="o">&gt;&gt;</span> ~/.zshrc
</code></pre></div></div>

<h2 id="reload-the-shell">Reload the shell</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">source</span> ~/.zshrc
</code></pre></div></div>

<h2 id="check-the-installation">Check the installation</h2>

<p>Check that we’re using the right version of Ruby, which already comes with Bundler installed:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ruby <span class="nt">-v</span>
ruby 3.4.7 <span class="o">(</span>2025-10-08 revision 7a5688e2a2<span class="o">)</span> +PRISM <span class="o">[</span>arm64-darwin24]

<span class="nv">$ </span>bundle <span class="nt">--version</span>
Bundler version 2.6.9
</code></pre></div></div>

<p>At this point, we already have Ruby <code class="language-plaintext highlighter-rouge">3.4.7</code> installed and activated!</p>

<h2 id="list-available-ruby-versions">List available Ruby versions</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>chruby
   ruby-3.3.6
   ruby-3.4.5
 <span class="k">*</span> ruby-3.4.7
</code></pre></div></div>

<h2 id="switch-between-ruby-versions">Switch between Ruby versions</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ruby <span class="nt">-v</span>
ruby 3.4.7 <span class="o">(</span>2025-10-08 revision 7a5688e2a2<span class="o">)</span> +PRISM <span class="o">[</span>arm64-darwin24]

<span class="nv">$ </span>chruby 3.3.6
<span class="nv">$ </span>ruby <span class="nt">-v</span>
ruby 3.3.6 <span class="o">(</span>2024-11-05 revision 75015d4c1f<span class="o">)</span> <span class="o">[</span>arm64-darwin24]

<span class="nv">$ </span>chruby 3.4.5
<span class="nv">$ </span>ruby <span class="nt">-v</span>
ruby 3.4.5 <span class="o">(</span>2025-07-16 revision 20cda200d3<span class="o">)</span> +PRISM <span class="o">[</span>arm64-darwin24]

<span class="nv">$ </span>chruby 3.4.7
<span class="nv">$ </span>ruby <span class="nt">-v</span>
ruby 3.4.7 <span class="o">(</span>2025-10-08 revision 7a5688e2a2<span class="o">)</span> +PRISM <span class="o">[</span>arm64-darwin24]
</code></pre></div></div>

<h2 id="set-the-ruby-version-in-the-project">Set the Ruby version in the project</h2>

<p>It’s recommended to create a <code class="language-plaintext highlighter-rouge">.ruby-version</code> file to both document the Ruby version and
enable the auto-switch mechanism.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cd </span>my_project
<span class="nv">$ </span><span class="nb">echo</span> <span class="s1">'3.4.5'</span> <span class="o">&gt;</span> .ruby-version
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">chruby</code> will auto-switch Ruby versions based on the presence of a <code class="language-plaintext highlighter-rouge">.ruby-version</code> file in
the folder we <code class="language-plaintext highlighter-rouge">cd</code> to.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ruby <span class="nt">-v</span>
ruby 3.4.7 <span class="o">(</span>2025-10-08 revision 7a5688e2a2<span class="o">)</span> +PRISM <span class="o">[</span>arm64-darwin24]

<span class="nv">$ </span><span class="nb">cd </span>my_project
<span class="nv">$ </span>ruby <span class="nt">-v</span>
ruby 3.4.5 <span class="o">(</span>2025-07-16 revision 20cda200d3<span class="o">)</span> +PRISM <span class="o">[</span>arm64-darwin24]

<span class="nv">$ </span><span class="nb">cd</span> ..
<span class="nv">$ </span>ruby <span class="nt">-v</span>
ruby 2.6.10p210 <span class="o">(</span>2022-04-12 revision 67958<span class="o">)</span> <span class="o">[</span>universal.arm64e-darwin24]
</code></pre></div></div>

<p>If you then <code class="language-plaintext highlighter-rouge">cd</code> into a different directory that either doesn’t have a <code class="language-plaintext highlighter-rouge">.ruby-version</code>
file or if the <code class="language-plaintext highlighter-rouge">.ruby-version</code> file is set to a Ruby version that <code class="language-plaintext highlighter-rouge">chruby</code> doesn’t know
about, then <code class="language-plaintext highlighter-rouge">chruby</code> will revert to the <em>system</em> Ruby on my Mac (<code class="language-plaintext highlighter-rouge">2.6.10</code> in this case).</p>

<p><strong>Notes</strong>:</p>
<ul>
  <li>This assumes that the <code class="language-plaintext highlighter-rouge">auto.sh</code> script has been sourced in the <code class="language-plaintext highlighter-rouge">.zshrc</code> file,
as described in one of the <a href="#configure-chruby-in-the-shell">previous sections</a>.</li>
  <li>Remember not to add any trailing newlines to this file, as mentioned
<a href="https://docs.netlify.com/configure-builds/manage-dependencies/#ruby">here</a>.</li>
</ul>

<h2 id="install-ruby-gems">Install Ruby gems</h2>

<p>We can now use Bundler to install the gems:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bundle <span class="nb">install</span>
</code></pre></div></div>

<p>Bundler is the standard tool in Ruby for managing project dependencies.</p>

<h3 id="installation-location">Installation location</h3>

<p>Gems could end up in different locations depending on how they are installed:</p>

<h4 id="1-gems-bundled-with-ruby">1. Gems bundled with Ruby</h4>

<ul>
  <li>Location: <code class="language-plaintext highlighter-rouge">~/.rubies/ruby-&lt;version&gt;/lib/ruby/gems/&lt;major&gt;.&lt;minor&gt;.0/</code></li>
  <li>Example: <code class="language-plaintext highlighter-rouge">~/.rubies/ruby-3.4.7/lib/ruby/gems/3.4.0/</code></li>
</ul>

<p>These are gems that ship with Ruby itself (like <code class="language-plaintext highlighter-rouge">bundler</code>, <code class="language-plaintext highlighter-rouge">irb</code>, <code class="language-plaintext highlighter-rouge">rake</code>, etc.) and are installed
when running <code class="language-plaintext highlighter-rouge">ruby-install</code>. The path uses the minor version format (<code class="language-plaintext highlighter-rouge">3.4.0</code>) so native extensions
stay compatible across patch releases (3.4.5, 3.4.6, 3.4.7, etc.).</p>

<h4 id="2-gems-installed-via-gem-install">2. Gems installed via <code class="language-plaintext highlighter-rouge">gem install</code></h4>

<ul>
  <li>Location: <code class="language-plaintext highlighter-rouge">~/.gem/ruby/&lt;full-version&gt;/</code></li>
  <li>Example: <code class="language-plaintext highlighter-rouge">~/.gem/ruby/3.4.7/</code></li>
</ul>

<p>When <code class="language-plaintext highlighter-rouge">chruby</code> is active, it sets <code class="language-plaintext highlighter-rouge">GEM_HOME</code> to this path using the full Ruby version.
Each Ruby installation (full version) has its own separate gem directory.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">echo</span> <span class="nv">$GEM_HOME</span>
/Users/&lt;username&gt;/.gem/ruby/3.4.7
</code></pre></div></div>

<h4 id="3-gems-installed-via-bundle-install-without-bundle_path">3. Gems installed via <code class="language-plaintext highlighter-rouge">bundle install</code> (without <code class="language-plaintext highlighter-rouge">BUNDLE_PATH</code>)</h4>

<ul>
  <li>Location: Same as <code class="language-plaintext highlighter-rouge">gem install</code> → <code class="language-plaintext highlighter-rouge">~/.gem/ruby/&lt;full-version&gt;/</code></li>
</ul>

<p>When Bundler has no custom path configured, it installs gems to the same location as <code class="language-plaintext highlighter-rouge">gem install</code>.
This means gems are shared across all projects using the same Ruby version.</p>

<p>Bundler doesn’t provide filesystem isolation for gems by default (see
<a href="#isolate-gems-per-project">Isolate gems per project</a>). Multiple versions of the same gem can
coexist in the gem installation directory. Instead, Bundler isolates gems at runtime by manipulating
the load path (<code class="language-plaintext highlighter-rouge">$LOAD_PATH</code>) to include only the gems specified in the project’s <code class="language-plaintext highlighter-rouge">Gemfile.lock</code>.</p>

<h4 id="4-gems-installed-via-bundle-install-with-bundle_path">4. Gems installed via <code class="language-plaintext highlighter-rouge">bundle install</code> (with <code class="language-plaintext highlighter-rouge">BUNDLE_PATH</code>)</h4>

<ul>
  <li>Location: <code class="language-plaintext highlighter-rouge">&lt;configured-path&gt;/ruby/&lt;major&gt;.&lt;minor&gt;.0/</code></li>
  <li>Example: <code class="language-plaintext highlighter-rouge">vendor/bundle/ruby/3.4.0/</code></li>
</ul>

<p>When <code class="language-plaintext highlighter-rouge">BUNDLE_PATH</code> is configured, Bundler installs gems in that path. <code class="language-plaintext highlighter-rouge">BUNDLE_PATH</code> can be set via:</p>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">BUNDLE_PATH</code> environment variable</li>
  <li>The <code class="language-plaintext highlighter-rouge">.bundle/config</code> file</li>
  <li>The <code class="language-plaintext highlighter-rouge">--deployment</code> flag (which defaults to <code class="language-plaintext highlighter-rouge">vendor/bundle</code>)</li>
</ul>

<p>It uses the minor version format (<code class="language-plaintext highlighter-rouge">3.4.0</code>) so upgrading from Ruby 3.4.5 to 3.4.7 doesn’t
require reinstalling gems.</p>

<p>See <a href="#isolate-gems-per-project">Isolate gems per project</a> for how to configure this.</p>

<h3 id="isolate-gems-per-project">Isolate gems per project</h3>

<p>We could also choose to use filesystem isolation per project by installing gems locally in
<code class="language-plaintext highlighter-rouge">vendor/bundle</code> and configuring Bundler to use it:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Add the Bundle path to the Bundle config</span>
<span class="nv">$ </span>bundle config <span class="nb">set</span> <span class="nt">--local</span> path <span class="s1">'vendor/bundle'</span>

<span class="c"># Install the gems in the Bundle path specified in the Bundle config</span>
<span class="nv">$ </span>bundle <span class="nb">install
</span>Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
<span class="c"># ...</span>
Bundle <span class="nb">complete</span><span class="o">!</span> 7 Gemfile dependencies, 40 gems now installed.
Bundled gems are installed into <span class="sb">`</span>./vendor/bundle<span class="sb">`</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">bundle config</code> command above creates a <code class="language-plaintext highlighter-rouge">.bundle/config</code> file that remembers this setting:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">BUNDLE_PATH</span><span class="pi">:</span> <span class="s2">"</span><span class="s">vendor/bundle"</span>
</code></pre></div></div>

<p>Subsequent bundle install commands will install gems in the <code class="language-plaintext highlighter-rouge">vendor/bundle</code> folder.</p>

<p>Remember to add these files to <code class="language-plaintext highlighter-rouge">.gitignore</code>:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"vendor/bundle/"</span> <span class="o">&gt;&gt;</span> .gitignore
<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">".bundle/"</span> <span class="o">&gt;&gt;</span> .gitignore
</code></pre></div></div>

<h2 id="check-the-gem-environment">Check the gem environment</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gem <span class="nb">env
</span>RubyGems Environment:
  - RUBYGEMS VERSION: 3.6.9
  - RUBY VERSION: 3.4.7 <span class="o">(</span>2025-10-08 patchlevel 58<span class="o">)</span> <span class="o">[</span>arm64-darwin24]
  - INSTALLATION DIRECTORY: /Users/&lt;username&gt;/.gem/ruby/3.4.7
  - USER INSTALLATION DIRECTORY: /Users/&lt;username&gt;/.local/share/gem/ruby/3.4.0
  - CREDENTIALS FILE: /Users/&lt;username&gt;/.local/share/gem/credentials
  - RUBY EXECUTABLE: /Users/&lt;username&gt;/.rubies/ruby-3.4.7/bin/ruby
  - GIT EXECUTABLE: /usr/bin/git
  - EXECUTABLE DIRECTORY: /Users/&lt;username&gt;/.gem/ruby/3.4.7/bin
  - SPEC CACHE DIRECTORY: /Users/&lt;username&gt;/.cache/gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /Users/&lt;username&gt;/.rubies/ruby-3.4.7/etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - arm64-darwin-24
  - GEM PATHS:
     - /Users/&lt;username&gt;/.gem/ruby/3.4.7
     - /Users/&lt;username&gt;/.rubies/ruby-3.4.7/lib/ruby/gems/3.4.0
  - GEM CONFIGURATION:
     - :update_sources <span class="o">=&gt;</span> <span class="nb">true</span>
     - :verbose <span class="o">=&gt;</span> <span class="nb">true</span>
     - :backtrace <span class="o">=&gt;</span> <span class="nb">true</span>
     - :bulk_threshold <span class="o">=&gt;</span> 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /Users/&lt;username&gt;/.gem/ruby/3.4.7/bin
     - /Users/&lt;username&gt;/.rubies/ruby-3.4.7/lib/ruby/gems/3.4.0/bin
     - /Users/&lt;username&gt;/.rubies/ruby-3.4.7/bin
     <span class="c"># ...</span>
</code></pre></div></div>

<h2 id="summary">Summary</h2>

<ul>
  <li>Manage Ruby versions using <code class="language-plaintext highlighter-rouge">chruby</code> + <code class="language-plaintext highlighter-rouge">ruby-install</code> + Bundler</li>
  <li>Simple installation and usability</li>
  <li><code class="language-plaintext highlighter-rouge">ruby-install</code> handles installing Ruby versions</li>
  <li><code class="language-plaintext highlighter-rouge">chruby</code> handles switching Ruby versions (also automatically via <code class="language-plaintext highlighter-rouge">.ruby-version</code> files)</li>
  <li>Bundler handles gem dependencies management via <code class="language-plaintext highlighter-rouge">Gemfile</code> and <code class="language-plaintext highlighter-rouge">Gemfile.lock</code>
    <ul>
      <li>Gem isolation per Ruby version</li>
      <li>Gem isolation per project at runtime: applications only load gems specified in the
<code class="language-plaintext highlighter-rouge">Gemfile.lock</code> file</li>
    </ul>
  </li>
</ul>

<p><strong><em>2025-11-29 - Update:</em></strong></p>

<ul>
  <li>All the sections are now up to date</li>
  <li>Ruby versions updated</li>
  <li>Expanded the section about installing Ruby gems</li>
  <li>Added a summary</li>
</ul>

<p><strong><em>2025-12-02 - Update:</em></strong></p>

<ul>
  <li>Restructured the <a href="#installation-location">Installation location</a> section with detailed subsections</li>
  <li>Clarified where gems are installed and why different paths use different version formats</li>
  <li>Added <code class="language-plaintext highlighter-rouge">$GEM_HOME</code> example</li>
  <li>Added note about Ruby <code class="language-plaintext highlighter-rouge">3.3.x</code> compilation issue on some macOS systems</li>
  <li>Fixed various consistency issues</li>
</ul>]]></content><author><name>Julio Trigo</name></author><category term="Ruby" /><category term="chruby" /><category term="ruby-install" /><category term="bundle" /><category term="ruby-version" /><category term="gem" /><summary type="html"><![CDATA[There are already quite a few guides and articles that explain how to install Ruby, so I don’t intend to write just another one. Instead, I’m going to document the steps I followed to install Ruby on my Mac, describe the approach I chose, and summarise the commands I used. These notes are meant to serve as my personal technical reference and to help clarify how the Ruby installation process works.]]></summary></entry><entry><title type="html">Migrating my website domain</title><link href="https://www.juliotrigo.com/articles/migrating-my-website-domain/" rel="alternate" type="text/html" title="Migrating my website domain" /><published>2020-05-10T22:00:00+01:00</published><updated>2020-05-13T18:20:00+01:00</updated><id>https://www.juliotrigo.com/articles/migrating-my-website-domain</id><content type="html" xml:base="https://www.juliotrigo.com/articles/migrating-my-website-domain/"><![CDATA[<p>I have been using the <code class="language-plaintext highlighter-rouge">blog</code> subdomain for this website since I started my blog around 2013 (on <a href="https://www.blogger.com">Blogger</a>, before I moved to <a href="https://pages.github.com/">GitHub Pages</a>). I did not want to build something myself for publishing my articles and Blogger gave me the option of using my own custom domain. Since I was already using <code class="language-plaintext highlighter-rouge">www</code> on my main website, I decided to go with <code class="language-plaintext highlighter-rouge">blog</code> instead.</p>

<!--more-->

<p>I have wanted to consolidate my websites in one domain name for a long time to have all my content available in a single place. This is also normally recommended for SEO.</p>

<p>However, it wasn’t until I read about <a href="https://www.w3.org/TR/webmention/">Webmention</a>, <a href="https://indieweb.org/">IndieWeb</a>, <a href="https://indieweb.org/POSSE">POSSE</a>, and <a href="https://indieweb.org/Web_sign-in">Web sign-in</a> that I decided to finally go ahead and move all my content under my primary domain: if I am going to use my personal web address as my ID then I need to decide what domain name I want to employ for that.</p>

<h2 id="should-i-use-www">Should I use www?</h2>

<p>So the first step was to decide the primary domain for my website: <code class="language-plaintext highlighter-rouge">www.juliotrigo.com</code>.</p>

<p><a href="https://www.yes-www.org/why-use-www/">Here</a> you can read about why it is recommended to use <code class="language-plaintext highlighter-rouge">www</code> instead of <em>apex</em> domains (also called <em>bare</em>, <em>naked</em>, or <em>root</em> domains) as the primary domain, which should be part of the <a href="https://www.mattcutts.com/blog/seo-advice-url-canonicalization/">canonical website URLs</a>.</p>

<h2 id="migration-changes-with-github-pages">Migration changes with GitHub Pages</h2>

<p>There is some documentation about <a href="https://help.github.com/en/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site">configuring</a> and <a href="https://help.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site">managing</a> custom domains with GitHub Pages out there.</p>

<p>These are the changes I made:</p>

<ul>
  <li><strong>Code</strong> (diff):</li>
</ul>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Jekyll _config.yml</span>

<span class="na">-url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://blog.juliotrigo.com"</span>
<span class="na">+url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://www.juliotrigo.com"</span>

<span class="c1"># I have started with play with https://www.w3.org/TR/webmention/</span>
<span class="na">webmentions</span><span class="pi">:</span>
<span class="pi">-</span>  <span class="na">username</span><span class="pi">:</span> <span class="s">blog.juliotrigo.com</span>
<span class="na">+  username</span><span class="pi">:</span> <span class="s">www.juliotrigo.com</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># CNAME

-blog.juliotrigo.com
+www.juliotrigo.com
</code></pre></div></div>

<ul>
  <li><strong>DNS</strong>:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># DNS config

DNS ENTRY       TYPE            DESTINATION/TARGET
@               A               185.199.108.153
@               A               185.199.109.153
@               A               185.199.110.153
@               A               185.199.111.153
blog            CNAME           www.juliotrigo.com.
www             CNAME           my-subdomain.github.io.
</code></pre></div></div>

<h3 id="github-pages-limitations">GitHub Pages limitations</h3>

<p>GitHub Pages had not been providing me all the freedom that I needed lately. For instance, by <a href="https://pages.github.com/versions/">restricting the Jekyll dependency versions that I can use</a>.</p>

<p>Additionally, I had a few <a href="https://github.community/t5/GitHub-Pages/Does-GitHub-Pages-Support-HTTPS-for-www-and-subdomains/td-p/7116">HTTPS issues</a> with my apex domain after the migration, as explained <a href="https://github.community/t5/GitHub-Pages/Does-GitHub-Pages-Support-HTTPS-for-www-and-subdomains/m-p/7202#M495">here</a>:</p>

<blockquote>
  <p>GitHub doesn’t currently support creating a certificate that covers both your root domain and your <code class="language-plaintext highlighter-rouge">www</code> subdomain. We only generate a certificate for the exact domain that you specify in the custom domain input box. (2018-05-10)</p>
</blockquote>

<p>I also wanted to redirect the old subdomain (<code class="language-plaintext highlighter-rouge">blog</code>) to the primary one (<code class="language-plaintext highlighter-rouge">www</code>).</p>

<p>Even if there’s already a way of solving some of those things, I decided to give <a href="https://www.netlify.com/">Netlify</a> a go.</p>

<h2 id="migrating-from-github-pages-to-netlify">Migrating from GitHub Pages to Netlify</h2>

<p>It was extremely simple to have it all set up with Netlify.</p>

<p>As part of this process, I had to ensure that:</p>
<ul>
  <li>The website was <strong>up and running</strong> with no errors</li>
  <li><strong>HTTPS</strong> was enabled and working</li>
  <li>All the relevant URLs were <strong>redirected</strong> to my primary domain</li>
</ul>

<h3 id="1-set-up-build-and-deploy-the-website">1) Set up, build and deploy the website</h3>

<p>It was done with just a few simple steps:</p>
<ul>
  <li>Sign up on Netlify</li>
  <li>Select the source code repository (<em>no code changes were required</em>)</li>
  <li>Create a new site</li>
  <li>Verify/amend the site settings (<em>the default values were good</em>)</li>
</ul>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Build command</span><span class="pi">:</span> <span class="s">jekyll build</span>
<span class="na">Publish directory</span><span class="pi">:</span> <span class="s">_site/</span>
</code></pre></div></div>

<ul>
  <li>Set environment variables to be used during the build process</li>
</ul>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">JEKYLL_ENV</span><span class="pi">:</span> <span class="s">production</span>
</code></pre></div></div>

<ul>
  <li>Build and deploy the website</li>
</ul>

<h3 id="2-https-setup">2) HTTPS setup</h3>

<ul>
  <li><strong>Netlify</strong>:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>my-subdomain.netlify.app: Default subdomain
www.juliotrigo.com: Primary domain
juliotrigo.com: Redirects automatically to primary domain
blog.juliotrigo.com: Domain alias
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Your site has HTTPS enabled
Domains: blog.juliotrigo.com, juliotrigo.com, www.juliotrigo.com
Auto-renews in 3 months
</code></pre></div></div>

<ul>
  <li><strong>DNS</strong>:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># DNS config

DNS ENTRY       TYPE            DESTINATION/TARGET
@               A               104.198.14.52
blog            CNAME           www.juliotrigo.com.
www             CNAME           my-subdomain.netlify.app.
</code></pre></div></div>

<h3 id="3-fix-redirects">3) Fix redirects</h3>

<p>Add <a href="https://docs.netlify.com/routing/redirects/">redirect rules</a>:</p>

<div class="language-apache highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># _redirects</span>

<span class="c"># Redirect default Netlify subdomain to primary domain</span>
<span class="nc">https</span>://my-subdomain.netlify.app/* https://www.juliotrigo.com/:splat 301!

<span class="c"># Redirect old subdomain to primary domain</span>
<span class="nc">https</span>://blog.juliotrigo.com/* https://www.juliotrigo.com/:splat 301!
</code></pre></div></div>

<p><a href="https://jekyllrb.com/docs/configuration/options/">Include</a> the <code class="language-plaintext highlighter-rouge">_redirects</code> file in the folder where the generated site will be placed (<code class="language-plaintext highlighter-rouge">_site</code>):</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Jekyll _config.yml</span>

<span class="na">include</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">_redirects</span><span class="pi">]</span>
</code></pre></div></div>

<h3 id="4-verify-all-the-relevant-urls">4) Verify all the relevant URLs</h3>

<p>Check that all the relevant URLs are redirected to my canonical URL: <code class="language-plaintext highlighter-rouge">https://www.juliotrigo.com</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># www subdomain
http://www.juliotrigo.com
http://www.juliotrigo.com/
https://www.juliotrigo.com
https://www.juliotrigo.com/

# Apex domain
http://juliotrigo.com
http://juliotrigo.com/
https://juliotrigo.com
https://juliotrigo.com/

# The old blog subdomain
http://blog.juliotrigo.com
http://blog.juliotrigo.com/
https://blog.juliotrigo.com
https://blog.juliotrigo.com/

# Netlify default subdomain
http://my-subdomain.netlify.app
http://my-subdomain.netlify.app/
https://my-subdomain.netlify.app
https://my-subdomain.netlify.app/
</code></pre></div></div>

<h2 id="things-ive-learned">Things I’ve learned</h2>

<ul>
  <li>The benefits of using <code class="language-plaintext highlighter-rouge">www</code> as the primary domain</li>
  <li>The functionality that Netlify provides on their <em>Starter</em> free plan is quite powerful and simple to use</li>
  <li>The SSL/TLS certificate that Netlify issues can cover extra subdomains (free of charge)</li>
  <li>The <code class="language-plaintext highlighter-rouge">_redirects</code> file is a simple way of doing HTTP redirects</li>
</ul>

<p><strong><em>2020-05-13 - Update:</em></strong></p>

<p>Set environment variables to be used during the build process.</p>]]></content><author><name>Julio Trigo</name></author><category term="domain names" /><category term="HTTPS" /><category term="DNS" /><category term="GitHub Pages" /><category term="Netlify" /><summary type="html"><![CDATA[I have been using the blog subdomain for this website since I started my blog around 2013 (on Blogger, before I moved to GitHub Pages). I did not want to build something myself for publishing my articles and Blogger gave me the option of using my own custom domain. Since I was already using www on my main website, I decided to go with blog instead.]]></summary></entry><entry><title type="html">Lato 2.0 Font Family</title><link href="https://www.juliotrigo.com/articles/lato-2-0-font-family/" rel="alternate" type="text/html" title="Lato 2.0 Font Family" /><published>2019-11-12T22:47:00+00:00</published><updated>2024-01-27T11:15:00+00:00</updated><id>https://www.juliotrigo.com/articles/lato-2-0-font-family</id><content type="html" xml:base="https://www.juliotrigo.com/articles/lato-2-0-font-family/"><![CDATA[<p>As part of a small redesign on this website, I wanted to use a high-quality and elegant font that <em>also looked good with text in italics</em> and <strong>displaying content in bold</strong>, but <strong><em>specially when combining both styles, which is something more difficult to find</em></strong>.</p>

<p>After doing some research and comparing a few different fonts, I started to use the <em>Lato</em> <a href="https://fonts.google.com/specimen/Lato">Google font</a>. However, even though it looked quite good, I was not fully convinced.</p>

<!--more-->

<p>After a few hours comparing different fonts, it became quite hard for me to spot differences between them so I called it a day. The next morning, a bit fresher, I decided to know a bit more about <em>Lato</em> so I went to its <a href="https://www.latofonts.com/lato-free-fonts/">website</a> to immediately see <strong><em>how beautiful</em></strong> the font looked on that page.</p>

<p>That font was different to the one I was currently using from Google Fonts, so I checked the content of that page and discovered a few interesting things:</p>
<ul>
  <li>The <em>Lato</em> website was using the <code class="language-plaintext highlighter-rouge">LatoLatinWeb</code> font family</li>
  <li>There’s a <code class="language-plaintext highlighter-rouge">2.0</code> (<code class="language-plaintext highlighter-rouge">2.015</code>) version of the <em>Lato</em> font family avail­able as a free down­load under the <a href="https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&amp;id=OFL">SIL Open Font License 1.1</a></li>
  <li>It is specified that:
    <blockquote>
      <p>The older ver­sion (1.0) of the Lato font fam­ily is avail­able on Google Fonts. We have no infor­ma­tion when Lato 2.0 will be avail­able on Google Fonts</p>
    </blockquote>
  </li>
</ul>

<p>This GitHub <a href="https://github.com/google/fonts/issues/6">issue</a> (opened on the 9th April 2015) explains why <em>Lato</em> <code class="language-plaintext highlighter-rouge">2.0</code> is still not available on Google Fonts. It seem that <em>Lato</em> <code class="language-plaintext highlighter-rouge">2.015</code> uses a newer version of <code class="language-plaintext highlighter-rouge">ttfauothint</code>, which now produces a different result. Apparently, there was a deployment of that font version on Google Fonts in January 2017, but it had to be rolled out because it affected quite a few users (<a href="https://github.com/google/fonts/issues/644">Overnight my Lato looks quite different</a>).</p>

<p>At that point, and taking all things into consideration, I decided that I still wanted to use the <code class="language-plaintext highlighter-rouge">2.0</code> version of the <em>Lato</em> font family on my website. This is how you can do it:</p>
<ul>
  <li>Download the <code class="language-plaintext highlighter-rouge">Lato2OFLWeb</code> <a href="https://www.latofonts.com/download/Lato2OFLWeb.zip">Webfonts</a>
    <ul>
      <li>In my case:<code class="language-plaintext highlighter-rouge">Version 2.015</code></li>
    </ul>
  </li>
  <li>Follow the instructions included in the <code class="language-plaintext highlighter-rouge">README-WEB.txt</code> file</li>
  <li>Select the font styles to be used
    <ul>
      <li>In my case: <code class="language-plaintext highlighter-rouge">LatoLatin-Regular</code>, <code class="language-plaintext highlighter-rouge">LatoLatin-Italic</code>, <code class="language-plaintext highlighter-rouge">LatoLatin-Bold</code>, and <code class="language-plaintext highlighter-rouge">LatoLatin-BoldItalic</code> from the <code class="language-plaintext highlighter-rouge">LatoLatin</code> group</li>
    </ul>
  </li>
  <li>Copy the selected font style files to the website location where the static content is served from</li>
  <li>Inspect the <code class="language-plaintext highlighter-rouge">latolatinfonts.css</code> style sheet and use the CSS rules for the selected font styles</li>
  <li>Use <code class="language-plaintext highlighter-rouge">LatoLatinWeb</code> as a <code class="language-plaintext highlighter-rouge">font-family</code></li>
  <li>Credit the authors of the <em>Lato</em> font for the original creation
    <ul>
      <li>In my case, done in the <a href="/license-copyright/">License &amp; copyright</a>
 page</li>
    </ul>
  </li>
</ul>

<p>Finally, just enjoy the <code class="language-plaintext highlighter-rouge">2.0</code> version of the <em>Lato</em> font family!</p>

<p><strong><em>2020-04-18 - Update:</em></strong></p>

<p>Text amendments.</p>]]></content><author><name>Julio Trigo</name></author><category term="lato" /><category term="css" /><category term="font-family" /><category term="web-design" /><summary type="html"><![CDATA[As part of a small redesign on this website, I wanted to use a high-quality and elegant font that also looked good with text in italics and displaying content in bold, but specially when combining both styles, which is something more difficult to find. After doing some research and comparing a few different fonts, I started to use the Lato Google font. However, even though it looked quite good, I was not fully convinced.]]></summary></entry><entry><title type="html">PyConES 2019 - A practical DDD approach to Nameko microservices</title><link href="https://www.juliotrigo.com/articles/pycones-2019-a-practical-ddd-approach-to-nameko-microservices/" rel="alternate" type="text/html" title="PyConES 2019 - A practical DDD approach to Nameko microservices" /><published>2019-10-07T19:50:00+01:00</published><updated>2024-01-27T11:15:00+00:00</updated><id>https://www.juliotrigo.com/articles/pycones-2019-a-practical-ddd-approach-to-nameko-microservices</id><content type="html" xml:base="https://www.juliotrigo.com/articles/pycones-2019-a-practical-ddd-approach-to-nameko-microservices/"><![CDATA[<p>Here you can find all the information about the talk that I gave at <a href="https://2019.es.pycon.org">PyConES 2019</a> on the 5th of October, 2019: <strong><em>A practical DDD approach to Nameko microservices</em></strong></p>

<p>Slides: <a href="https://slides.com/juliotrigo/pycones2019-a-practical-ddd-approach-to-nameko-microservices">PyConES 2019 - A practical DDD approach to Nameko microservices</a></p>

<!--more-->

<p>
    <div class="youtube-container">
        <iframe title="A practical domain driven design approach to Nameko microservices - Julio Trigo" class="youtube-iframe" src="https://www.youtube.com/embed/4O4jo56fgXE" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
    </div>
</p>

<p>Here’s the excerpt of the talk:</p>

<p><em><strong>Nameko</strong> is a “microservices framework for Python that lets service developers concentrate on application logic and encourages testability.”. It’s easy to use, has an elegant design and an open source community and ecosystem behind it. In this talk, we will show the basics of how to write microservices using Nameko and the types of extensions and communication protocols that are available.</em></p>

<p><em>We will also show <strong>a practical domain-driven design (DDD) approach to building a microservices architecture</strong>, showing how the design of the solution is driven by the domain of the application, the different types of services that we create (application/facades, domain), what their responsibilities are and how they can communicate with each other.</em></p>

<p><em>Finally, we will discuss one of the most important things in software design: how/when to <strong>split our code into different components</strong> (services, dependencies, modules, functions, etc.) so that they serve a single purpose, are easy to understand/extend and “fit in your head”.</em></p>

<p><strong><em>2020-04-18 - Update:</em></strong></p>

<p>YouTube video added.</p>]]></content><author><name>Julio Trigo</name></author><category term="python" /><category term="nameko" /><category term="microservices" /><category term="software design" /><category term="domain-driven design" /><summary type="html"><![CDATA[Here you can find all the information about the talk that I gave at PyConES 2019 on the 5th of October, 2019: A practical DDD approach to Nameko microservices Slides: PyConES 2019 - A practical DDD approach to Nameko microservices]]></summary></entry><entry><title type="html">Nameko Eventlog Dispatcher</title><link href="https://www.juliotrigo.com/articles/nameko-eventlog-dispatcher/" rel="alternate" type="text/html" title="Nameko Eventlog Dispatcher" /><published>2017-08-08T09:25:05+01:00</published><updated>2020-05-08T19:00:00+01:00</updated><id>https://www.juliotrigo.com/articles/nameko-eventlog-dispatcher</id><content type="html" xml:base="https://www.juliotrigo.com/articles/nameko-eventlog-dispatcher/"><![CDATA[<p>Here at <a href="https://twitter.com/sohonet">Sohonet</a>, we build our products backend following a microservices architecture.</p>

<p>Our services are built using <a href="https://github.com/nameko/nameko">Nameko</a>, a microservices framework for Python that <em>“lets service developers concentrate on application logic and encourages testability”</em>.</p>

<p>Nameko encourages the use of dependency injection and provides an easy way of adding <em>dependencies</em> to our services.<!--more--></p>

<h2 id="our-need">Our need</h2>

<p>There are many cases where we want to react to some of the events that happen in our applications. For instance, in our <a href="https://www.sohonet.com/clearview-flex/">ClearView Flex</a> real time collaboration application, we want to log some data for some of our events and also be able to programatically query that data later on. Some examples of these events are: <em>streaming session generated</em>, <em>attendee notified</em>, <em>streaming started</em>, etc.</p>

<p>Nameko already has an <code class="language-plaintext highlighter-rouge">EventDispatcher</code> dependency provider that can be used to dispatch events. However, what we need is to be able to dispatch both custom event data and some <strong>metadata</strong> related to each one of those events.</p>

<p>Additionally, since what we need in this case is to log events data, we want to avoid having to handle each one of those event types individually.</p>

<h2 id="our-solution">Our solution</h2>

<p>In order to achieve that, we have built <a href="https://github.com/sohonetlabs/nameko-eventlog-dispatcher"><code class="language-plaintext highlighter-rouge">nameko-eventlog-dispatcher</code></a>, a <em>“Nameko dependency provider that dispatches log data using Events (Pub-Sub)”</em>.</p>

<p>This dependency provider inherits from <code class="language-plaintext highlighter-rouge">EventDispatcher</code>, but enriches the event data with the metadata that we need. It also provides an <strong><em>auto capture</em></strong> mode, that allows us to log all the calls made to any of the entrypoints in our service.</p>

<h3 id="dispatching-event-log-data">Dispatching event log data</h3>

<p>In order to use the dependency, we need to include the <code class="language-plaintext highlighter-rouge">EventLogDispatcher</code> dependency provider in our service class and manually call it to dispatch an event:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">nameko.rpc</span> <span class="kn">import</span> <span class="n">rpc</span>
<span class="kn">from</span> <span class="n">nameko_eventlog_dispatcher</span> <span class="kn">import</span> <span class="n">EventLogDispatcher</span>


<span class="k">class</span> <span class="nc">FooService</span><span class="p">:</span>

    <span class="n">name</span> <span class="o">=</span> <span class="sh">'</span><span class="s">foo</span><span class="sh">'</span>

    <span class="n">eventlog_dispatcher</span> <span class="o">=</span> <span class="nc">EventLogDispatcher</span><span class="p">()</span>

    <span class="nd">@rpc</span>
    <span class="k">def</span> <span class="nf">foo_method</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="nf">eventlog_dispatcher</span><span class="p">(</span>
          <span class="sh">'</span><span class="s">foo_event_type</span><span class="sh">'</span><span class="p">,</span> <span class="p">{</span><span class="sh">'</span><span class="s">value</span><span class="sh">'</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span> <span class="n">metadata</span><span class="o">=</span><span class="p">{</span><span class="sh">'</span><span class="s">meta</span><span class="sh">'</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span>
        <span class="p">)</span>
</code></pre></div></div>

<p>Calling <code class="language-plaintext highlighter-rouge">foo_method</code> dispatches an event from the <code class="language-plaintext highlighter-rouge">foo</code> service with <code class="language-plaintext highlighter-rouge">log_event</code> as the event type. However <code class="language-plaintext highlighter-rouge">foo_event_type</code> will be the event type included in the event metadata.</p>

<p><code class="language-plaintext highlighter-rouge">event_type</code>, <code class="language-plaintext highlighter-rouge">event_data</code> (optional) and <code class="language-plaintext highlighter-rouge">metadata</code> (optional) can be provided as arguments. Both <code class="language-plaintext highlighter-rouge">event_data</code> and <code class="language-plaintext highlighter-rouge">metadata</code> must be dictionaries and contain JSON <strong>serializable</strong> data.</p>

<p>Then, any Nameko service will be able to handle this event.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">nameko.events</span> <span class="kn">import</span> <span class="n">event_handler</span>


<span class="k">class</span> <span class="nc">BarService</span><span class="p">:</span>

    <span class="n">name</span> <span class="o">=</span> <span class="sh">'</span><span class="s">bar</span><span class="sh">'</span>

    <span class="nd">@event_handler</span><span class="p">(</span><span class="sh">'</span><span class="s">foo</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">log_event</span><span class="sh">'</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">foo_log_event_handler</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">body</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">`body` will contain the event log data.</span><span class="sh">"""</span>
</code></pre></div></div>

<h3 id="auto-capture-enabled">Auto capture enabled</h3>

<p>When <strong><em>auto capture</em></strong> is enabled, a Nameko event is automatically dispatched every time an entrypoint is fired.</p>

<p>We can achieve that by overriding the <code class="language-plaintext highlighter-rouge">worker_setup</code> method in the dependency provider, which is called before a service worker executes a task when an entrypoint is fired.</p>

<h3 id="format-of-the-event-log-data">Format of the event log data</h3>

<p>This is an example of event data:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
  <span class="sh">"</span><span class="s">service_name</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">foo</span><span class="sh">"</span><span class="p">,</span>
  <span class="sh">"</span><span class="s">entrypoint_protocol</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">Rpc</span><span class="sh">"</span><span class="p">,</span>
  <span class="sh">"</span><span class="s">entrypoint_name</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">foo_method</span><span class="sh">"</span><span class="p">,</span>
  <span class="sh">"</span><span class="s">call_id</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">foo.foo_method.d7e907ee-9425-48a6-84e6-89db19e3ce50</span><span class="sh">"</span><span class="p">,</span>
  <span class="sh">"</span><span class="s">call_stack</span><span class="sh">"</span><span class="p">:</span> <span class="p">[</span>
    <span class="sh">"</span><span class="s">standalone_rpc_proxy.call.3f349ea4-ed3e-4a3b-93d0-a36fbf928ecb</span><span class="sh">"</span><span class="p">,</span>
    <span class="sh">"</span><span class="s">bla.bla_method.21d623b4-edc4-4232-9957-4fad72533b75</span><span class="sh">"</span><span class="p">,</span>
    <span class="sh">"</span><span class="s">foo.foo_method.d7e907ee-9425-48a6-84e6-89db19e3ce50</span><span class="sh">"</span>
  <span class="p">],</span>

  <span class="sh">"</span><span class="s">event_type</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">foo_event_type</span><span class="sh">"</span><span class="p">,</span>  <span class="c1"># the kind of event being dispatched: "session_created", "entrypoint_fired"...
</span>  <span class="sh">"</span><span class="s">timestamp</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">2017-06-12T13:48:16+00:00</span><span class="sh">"</span><span class="p">,</span>

  <span class="sh">"</span><span class="s">meta</span><span class="sh">"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>  <span class="c1"># extra information provided as "metadata"
</span>  <span class="sh">"</span><span class="s">data</span><span class="sh">"</span><span class="p">:</span> <span class="p">{</span><span class="sh">"</span><span class="s">value</span><span class="sh">"</span><span class="p">:</span> <span class="mi">1</span><span class="p">}</span>  <span class="c1"># extra information provided as "event_data"
</span><span class="p">}</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">data</code> attribute will contain the event data provided when the event was dispatched. If the event was automatically dispatched (<strong><em>auto capture</em></strong>) then <code class="language-plaintext highlighter-rouge">data</code> will be empty.</p>

<p>If <code class="language-plaintext highlighter-rouge">metadata</code> was provided, then its elements will be included as top level attributes.</p>

<h3 id="setup">Setup</h3>

<p>An <code class="language-plaintext highlighter-rouge">EVENTLOG_DISPATCHER</code> element can be added (optional) to our Nameko configuration file to override some of the setup default values:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## config.yaml</span>

<span class="na">EVENTLOG_DISPATCHER</span><span class="pi">:</span>
  <span class="na">auto_capture</span><span class="pi">:</span> <span class="kc">true</span>  <span class="c1"># enables auto capture mode</span>
  <span class="na">entrypoints_to_exclude</span><span class="pi">:</span> <span class="pi">[]</span>  <span class="c1"># list of entrypoint names to exclude when auto capture mode is enabled</span>
  <span class="na">event_type</span><span class="pi">:</span> <span class="s">log_event</span>  <span class="c1"># event type used to dispatch all the events</span>
</code></pre></div></div>

<h2 id="summary">Summary</h2>

<p>The <a href="https://github.com/sohonetlabs/nameko-eventlog-dispatcher"><code class="language-plaintext highlighter-rouge">nameko-eventlog-dispatcher</code></a> library can be installed from PyPI using pip:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pip <span class="nb">install </span>nameko-eventlog-dispatcher
</code></pre></div></div>

<p>By overriding the existing <code class="language-plaintext highlighter-rouge">EventDispatcher</code> Nameko dependency provider, we get all its functionally for free, making it also easier to add our custom logic that both dispatches events and adds the metadata that we need.</p>

<p>We’ve also tried to limit the internal Nameko components that we use in our code to the minimum in order to reduce coupling and prevent incompatibilities with future Nameko releases if its internal implementation changes.</p>

<p>All the log events are dispatched using the same event type (<code class="language-plaintext highlighter-rouge">log_event</code>) and are grouped per service:</p>

<ul>
  <li>Dispatching all the log events using the same <em>event type</em> makes it easier to add new events for our services. The original event type used when the event is dispatched is included in the <code class="language-plaintext highlighter-rouge">event_type</code> metadata attribute.</li>
  <li>Log events are individually handled per service, rather than grouping them for all our services. This allows us to have more granular control over what we log and when we start handling log events for a service. It creates different queues per service in <code class="language-plaintext highlighter-rouge">RabbitMQ</code> which could be beneficial in terms of performance, if the amount of logs varies significantly between services.</li>
</ul>

<p><strong><em>2019-01-28 - Update:</em></strong></p>

<p>A new version of the library has been released: <a href="https://pypi.org/project/nameko-eventlog-dispatcher/"><code class="language-plaintext highlighter-rouge">0.3.0</code></a>.</p>

<p>We’ve dropped support for previous <a href="https://github.com/nameko/nameko">Nameko</a> versions: it only officially supports <a href="https://github.com/nameko/nameko/releases/tag/v2.11.0"><code class="language-plaintext highlighter-rouge">v2.11.0</code></a> now, which is the latest release on the <code class="language-plaintext highlighter-rouge">2.x</code> branch at the moment.</p>

<p><strong><em>2019-03-21 - Update:</em></strong></p>

<p>A new version of the library has been released: <a href="https://pypi.org/project/nameko-eventlog-dispatcher/"><code class="language-plaintext highlighter-rouge">0.4.1</code></a>.</p>

<p>We’ve added support for older <a href="https://github.com/nameko/nameko">Nameko</a> versions, including the latest one in the <code class="language-plaintext highlighter-rouge">2.x</code> series: <code class="language-plaintext highlighter-rouge">2.6</code>, <code class="language-plaintext highlighter-rouge">2.7</code>, <code class="language-plaintext highlighter-rouge">2.8</code>, <code class="language-plaintext highlighter-rouge">2.9</code>, <code class="language-plaintext highlighter-rouge">2.10</code>, <code class="language-plaintext highlighter-rouge">2.11</code>, <code class="language-plaintext highlighter-rouge">2.12</code>.</p>]]></content><author><name>Julio Trigo</name></author><category term="nameko" /><category term="python" /><category term="microservices" /><summary type="html"><![CDATA[Here at Sohonet, we build our products backend following a microservices architecture. Our services are built using Nameko, a microservices framework for Python that “lets service developers concentrate on application logic and encourages testability”. Nameko encourages the use of dependency injection and provides an easy way of adding dependencies to our services.]]></summary></entry><entry><title type="html">PyConES 2015 - Distributed services</title><link href="https://www.juliotrigo.com/articles/pycones-2015-distributed-services/" rel="alternate" type="text/html" title="PyConES 2015 - Distributed services" /><published>2016-02-02T19:40:00+00:00</published><updated>2020-05-08T19:00:00+01:00</updated><id>https://www.juliotrigo.com/articles/pycones-2015-distributed-services</id><content type="html" xml:base="https://www.juliotrigo.com/articles/pycones-2015-distributed-services/"><![CDATA[<p>Here you can find all the information about the talk that I gave at <a href="http://2015.es.pycon.org">PyConES 2015</a> on the 22nd of November, 2015: <strong><em>Having it All: Distributed services with Django, Boto, and SQS queues</em></strong></p>

<p>Slides: <a href="https://slides.com/juliotrigo/pycones2015-distributed-services">PyConES 2015 - Distributed Services</a></p>

<!--more-->

<p>
    <div class="youtube-container">
        <iframe title="Having it All: Distributed services with Django, Boto, and SQS queues - Julio Trigo" class="youtube-iframe" src="https://www.youtube.com/embed/LYVfOfR3mp0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
    </div>
</p>

<p>Here’s the excerpt of the talk:</p>

<p><em>How do you let untrained people in your company run sensitive processes on different remote servers? Processes that must run asynchronously and sequentially while accessing different common resources? And how do you do it quickly and make it robust?</em></p>

<p><em>I will show how we used Django, SQS and Boto to create a distributed and decoupled solution that let users invoke services asynchronously, which is secure, scalable and ensures that processes using common resources ran in sequence.</em></p>]]></content><author><name>Julio Trigo</name></author><category term="python" /><category term="django" /><category term="boto" /><category term="sqs" /><summary type="html"><![CDATA[Here you can find all the information about the talk that I gave at PyConES 2015 on the 22nd of November, 2015: Having it All: Distributed services with Django, Boto, and SQS queues Slides: PyConES 2015 - Distributed Services]]></summary></entry><entry><title type="html">Unicode strings and bytestrings in Python 2</title><link href="https://www.juliotrigo.com/articles/unicode-strings-and-bytestrings-in-python-2/" rel="alternate" type="text/html" title="Unicode strings and bytestrings in Python 2" /><published>2015-04-21T20:24:00+01:00</published><updated>2020-05-08T19:00:00+01:00</updated><id>https://www.juliotrigo.com/articles/unicode-strings-and-bytestrings-in-python-2</id><content type="html" xml:base="https://www.juliotrigo.com/articles/unicode-strings-and-bytestrings-in-python-2/"><![CDATA[<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"&lt;stdin&gt;"</span>, line 1, <span class="k">in</span> &lt;module&gt;
UnicodeEncodeError: <span class="s1">'ascii'</span> codec can’t encode character u<span class="s1">'\u03b1'</span>
<span class="k">in </span>position 0: ordinal not <span class="k">in </span>range<span class="o">(</span>128<span class="o">)</span>
</code></pre></div></div>

<p>Does this Python exception look familiar? Most Python developers have seen this at least once.</p>

<p>Character sets, encodings, Unicode and all that stuff are hard to deal with until you fully understand what is going on behind the scenes.<!--more--> Please find below a few web pages that I find essential:</p>

<ul>
  <li>
    <p><a href="https://www.joelonsoftware.com/articles/Unicode.html">The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)</a> by Joel Spolsky</p>
  </li>
  <li>
    <p><a href="https://docs.python.org/2/howto/unicode.html">Unicode HOWTO — Python 2.7.9 documentation</a></p>
  </li>
  <li>
    <p><a href="https://docs.python.org/2/library/codecs.html#encodings-and-unicode">7.8. codecs — Codec registry and base classes — Python 2.7.9 documentation</a></p>
  </li>
</ul>

<p>What I am going to do is to provide some Unicode and bytestring examples using Python 2 to help understand them better.</p>

<p>Let’s say that we want to work with some Greek characters, which cannot be represented in ASCII (0-127): α β γ ε …</p>

<p>We can start creating them as Unicode characters.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> a <span class="o">=</span> u<span class="s1">'\u03b1'</span>
<span class="o">&gt;&gt;&gt;</span> b <span class="o">=</span> u<span class="s1">'\u03b2'</span>
<span class="o">&gt;&gt;&gt;</span> g <span class="o">=</span> u<span class="s1">'\u03b3'</span>

<span class="o">&gt;&gt;&gt;</span> a, b, g
<span class="o">(</span>u<span class="s1">'\u03b1'</span>, u<span class="s1">'\u03b2'</span>, u<span class="s1">'\u03b3'</span><span class="o">)</span>

<span class="o">&gt;&gt;&gt;</span> print a, b, g
α β γ
</code></pre></div></div>

<p>In <strong>Unicode</strong>, characters are represented by code points: integer values usually denoted in base 16.</p>

<p>We cannot represent them using the <strong>ASCII</strong> character-encoding scheme (7 bits, 0-127), which is the default encoding in Python 2. So it is the one used (by default) when converting Unicode characters into bytestrings (str in Python 2).</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> alphabet <span class="o">=</span> <span class="s1">'{}{}{}{}'</span>.format<span class="o">(</span>a, b, g, <span class="s1">'d'</span><span class="o">)</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"&lt;stdin&gt;"</span>, line 1, <span class="k">in</span> &lt;module&gt;
UnicodeEncodeError: <span class="s1">'ascii'</span> codec can’t encode character u<span class="s1">'\u03b1'</span>
<span class="k">in </span>position 0: ordinal not <span class="k">in </span>range<span class="o">(</span>128<span class="o">)</span>
</code></pre></div></div>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> alphabet <span class="o">=</span> u<span class="s1">'{}{}{}{}'</span>.format<span class="o">(</span>a, b, g, <span class="s1">'d'</span><span class="o">)</span>

<span class="o">&gt;&gt;&gt;</span> alphabet
u<span class="s1">'\u03b1\u03b2\u03b3d'</span>

<span class="o">&gt;&gt;&gt;</span> print alphabet
αβγd
</code></pre></div></div>

<p>A Unicode string is a sequence of code points (integers). In order to represent Unicode strings as a sequence of bytes we need to encode them using a character encoding. <strong>UTF-8</strong> is a character encoding capable of encoding all possible code points in Unicode.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> alphabet_str <span class="o">=</span> alphabet.encode<span class="o">(</span><span class="s1">'utf-8'</span><span class="o">)</span>

<span class="o">&gt;&gt;&gt;</span> alphabet_str
<span class="s1">'\xce\xb1\xce\xb2\xce\xb3d'</span>

<span class="o">&gt;&gt;&gt;</span> print alphabet_str
αβγd
</code></pre></div></div>

<p>Now, we have a Python str (UTF-8 encoding): a sequence of bytes representing the Unicode characters.</p>

<p>If a character encoding is not specified, then the <strong>encode</strong> method will assume that we want to use ASCII and will fail because those characters cannot be represented in ASCII.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> alphabet_str <span class="o">=</span> alphabet.encode<span class="o">()</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"&lt;stdin&gt;"</span>, line 1, <span class="k">in</span> &lt;module&gt;
UnicodeEncodeError: <span class="s1">'ascii'</span> codec can’t encode characters
<span class="k">in </span>position 0-2: ordinal not <span class="k">in </span>range<span class="o">(</span>128<span class="o">)</span>
</code></pre></div></div>

<p>We cannot represent those characters in <strong>latin-1</strong> (<strong>ISO-8859-1</strong>) either.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> alphabet_str <span class="o">=</span> alphabet.encode<span class="o">(</span><span class="s1">'latin-1'</span><span class="o">)</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"&lt;stdin&gt;"</span>, line 1, <span class="k">in</span> &lt;module&gt;
UnicodeEncodeError: <span class="s1">'latin-1'</span> codec can’t encode characters
<span class="k">in </span>position 0-2: ordinal not <span class="k">in </span>range<span class="o">(</span>256<span class="o">)</span>
</code></pre></div></div>

<p>And, as we expect, we also get an error if we try to decode the Unicode string (which does not make sense).</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> alphabet_str <span class="o">=</span> alphabet.decode<span class="o">(</span><span class="s1">'utf-8'</span><span class="o">)</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"&lt;stdin&gt;"</span>, line 1, <span class="k">in</span> &lt;module&gt;
  File <span class="s2">"/System/Library/Frameworks/Python.framework/Versions/
2.7/lib/python2.7/encodings/utf_8.py"</span>, line 16, <span class="k">in </span>decode
    <span class="k">return </span>codecs.utf_8_decode<span class="o">(</span>input, errors, True<span class="o">)</span>
UnicodeEncodeError: <span class="s1">'ascii'</span> codec can’t encode characters
<span class="k">in </span>position 0-2: ordinal not <span class="k">in </span>range<span class="o">(</span>128<span class="o">)</span>
</code></pre></div></div>

<p>Once we have the bytestring, we can <strong>decode</strong> it using the UTF-8 character encoding, and get back the original Unicode string.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> alphabet_u <span class="o">=</span> alphabet_str.decode<span class="o">(</span><span class="s1">'utf-8'</span><span class="o">)</span>

<span class="o">&gt;&gt;&gt;</span> alphabet_u
u<span class="s1">'\u03b1\u03b2\u03b3d'</span>

<span class="o">&gt;&gt;&gt;</span> print<span class="o">(</span>alphabet_u<span class="o">)</span>
αβγd
</code></pre></div></div>

<p>Again, we cannot encode a bytestring that was already encoded using UTF-8 (it does not make sense either).</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> alphabet_u <span class="o">=</span> alphabet_str.encode<span class="o">(</span><span class="s1">'utf-8'</span><span class="o">)</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"&lt;stdin&gt;"</span>, line 1, <span class="k">in</span> &lt;module&gt;
UnicodeDecodeError: <span class="s1">'ascii'</span> codec can’t decode byte 0xce
<span class="k">in </span>position 0: ordinal not <span class="k">in </span>range<span class="o">(</span>128<span class="o">)</span>
</code></pre></div></div>

<p>We can see that all those variables have different types:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="nb">type</span><span class="o">(</span>alphabet<span class="o">)</span>
&lt;<span class="nb">type</span> <span class="s1">'unicode'</span><span class="o">&gt;</span>

<span class="o">&gt;&gt;&gt;</span> <span class="nb">type</span><span class="o">(</span>alphabet_str<span class="o">)</span>
&lt;<span class="nb">type</span> <span class="s1">'str'</span><span class="o">&gt;</span>

<span class="o">&gt;&gt;&gt;</span> <span class="nb">type</span><span class="o">(</span>alphabet_u<span class="o">)</span>
&lt;<span class="nb">type</span> <span class="s1">'unicode'</span><span class="o">&gt;</span>
</code></pre></div></div>

<p>And different lengths.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> len<span class="o">(</span>alphabet_str<span class="o">)</span>
7

<span class="o">&gt;&gt;&gt;</span> len<span class="o">(</span>alphabet_u<span class="o">)</span>
4
</code></pre></div></div>

<p>So, in order to convert types:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">s</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="n">encoding</span><span class="p">)</span>  <span class="c1"># &lt;type 'str'&gt; to &lt;type 'unicode'&gt;
</span><span class="n">u</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="n">encoding</span><span class="p">)</span>  <span class="c1"># &lt;type 'unicode'&gt; to &lt;type 'str'&gt;
</span></code></pre></div></div>

<p>Additionally, we need to keep in mind that we can write Unicode literals in any encoding using Python. In order to do that, we have to declare the encoding being used by including a special comment as either the first or second line of the source file.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># -*- coding: latin-1 -*-
</span>
<span class="c1"># -*- coding: utf-8 -*-
</span></code></pre></div></div>

<p>Unicode literals are written as strings prefixed with the <code class="language-plaintext highlighter-rouge">'u'</code> or <code class="language-plaintext highlighter-rouge">'U'</code> character.</p>

<p>Below, we can see some examples of how the same string could be a Unicode or a bytestring string just depending on whether we write it as a Unicode literal or not.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> u<span class="s1">'ε'</span>
u<span class="s1">'\u03b5'</span>

<span class="o">&gt;&gt;&gt;</span> <span class="s1">'ε'</span>
<span class="s1">'\xce\xb5'</span>

<span class="o">&gt;&gt;&gt;</span> alphabet2 <span class="o">=</span> u<span class="s1">'{}{}{}{}'</span>.format<span class="o">(</span>a, b, g, u<span class="s1">'ε'</span><span class="o">)</span>

<span class="o">&gt;&gt;&gt;</span> alphabet2
u<span class="s1">'\u03b1\u03b2\u03b3\u03b5'</span>

<span class="o">&gt;&gt;&gt;</span> alphabet2 <span class="o">=</span> u<span class="s1">'{}{}{}{}'</span>.format<span class="o">(</span>a, b, g, <span class="s1">'ε'</span>.decode<span class="o">(</span><span class="s1">'utf-8'</span><span class="o">))</span>

<span class="o">&gt;&gt;&gt;</span> alphabet2
u<span class="s1">'\u03b1\u03b2\u03b3\u03b5'</span>

<span class="o">&gt;&gt;&gt;</span> print alphabet2
αβγε

<span class="o">&gt;&gt;&gt;</span> alphabet2 <span class="o">=</span> u<span class="s1">'{}{}{}{}'</span>.format<span class="o">(</span>a, b, g, <span class="s1">'ε'</span><span class="o">)</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"&lt;stdin&gt;"</span>, line 1, <span class="k">in</span> &lt;module&gt;
UnicodeDecodeError: <span class="s1">'ascii'</span> codec can’t decode byte 0xce
<span class="k">in </span>position 0: ordinal not <span class="k">in </span>range<span class="o">(</span>128<span class="o">)</span>
</code></pre></div></div>

<p>Finally, we can see how we may get different bytestrings when encoding the same Unicode string using different character encodings.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> u<span class="s1">'nona'</span>.encode<span class="o">(</span><span class="s1">'utf-8'</span><span class="o">)</span>
<span class="s1">'nona'</span>

<span class="o">&gt;&gt;&gt;</span> u<span class="s1">'nona'</span>.encode<span class="o">(</span><span class="s1">'latin-1'</span><span class="o">)</span>
<span class="s1">'nona'</span>

<span class="o">&gt;&gt;&gt;</span> u<span class="s1">'ñóñà'</span>.encode<span class="o">(</span><span class="s1">'utf-8'</span><span class="o">)</span>
<span class="s1">'\xc3\xb1\xc3\xb3\xc3\xb1\xc3\xa0'</span>

<span class="o">&gt;&gt;&gt;</span> u<span class="s1">'ñóñà'</span>.encode<span class="o">(</span><span class="s1">'latin-1'</span><span class="o">)</span>
<span class="s1">'\xf1\xf3\xf1\xe0'</span>
</code></pre></div></div>]]></content><author><name>Julio Trigo</name></author><category term="python" /><category term="unicode" /><category term="UTF-8" /><summary type="html"><![CDATA[Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; UnicodeEncodeError: 'ascii' codec can’t encode character u'\u03b1' in position 0: ordinal not in range(128) Does this Python exception look familiar? Most Python developers have seen this at least once. Character sets, encodings, Unicode and all that stuff are hard to deal with until you fully understand what is going on behind the scenes.]]></summary></entry><entry><title type="html">Deploying Django with Apache and mod_wsgi</title><link href="https://www.juliotrigo.com/articles/django-with-apache-and-modwsgi/" rel="alternate" type="text/html" title="Deploying Django with Apache and mod_wsgi" /><published>2014-01-20T20:18:00+00:00</published><updated>2020-05-08T19:00:00+01:00</updated><id>https://www.juliotrigo.com/articles/deploying-django-with-apache-and-mod-wsgi</id><content type="html" xml:base="https://www.juliotrigo.com/articles/django-with-apache-and-modwsgi/"><![CDATA[<p>The aim of this article is to explain how to deploy a Django site with Apache and WSGI on Linux (Ubuntu), considering that neither <code class="language-plaintext highlighter-rouge">apache2</code> nor <code class="language-plaintext highlighter-rouge">mod_wsgi</code> have been previously installed in the system. I will use the deployment of my personal website as an example.
<!--more--></p>
<h2 id="wsgi">WSGI</h2>

<p><a href="https://wsgi.readthedocs.io">WSGI</a> (Web Server Gateway Interface) is the Python standard (<a href="https://www.python.org/dev/peps/pep-3333/">PEP 3333</a>) for web servers and applications. It is a specification that describes how web servers communicate with web applications.</p>

<p>There are many frameworks that support WSGI. Django and Flask are two of them.</p>

<h2 id="httpd---apache2-web-server">HTTPD - Apache2 Web Server</h2>

<p>Apache is the most commonly used Web Server on Linux. It can be installed using apt-get:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>apache2
</code></pre></div></div>

<p>We can check the Apache version by doing:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>/usr/sbin/apache2 <span class="nt">-v</span>
Server version: Apache/2.4.6 <span class="o">(</span>Ubuntu<span class="o">)</span>
Server built: Dec 5 2013 18:32:22
</code></pre></div></div>

<p>The Apache setup files will be placed in <code class="language-plaintext highlighter-rouge">/etc/apache2/</code></p>

<h2 id="mod_wsgi">mod_wsgi</h2>

<p><a href="https://code.google.com/archive/p/modwsgi/"><code class="language-plaintext highlighter-rouge">mod_wsgi</code></a> is an Apache module that can host any Python application which supports the Python WSGI interface.</p>

<p><code class="language-plaintext highlighter-rouge">mod_wsgi</code> has two primary modes of operation:</p>

<ul>
  <li><em>Embedded mode</em>
    <ul>
      <li>WSGI applications run within the actual Apache child processes.</li>
      <li>WSGI applications share the same processes as other Apache hosted applications.</li>
    </ul>
  </li>
  <li><em>Daemon mode</em>
    <ul>
      <li>Available with Apache 2.X on UNIX.</li>
      <li>WSGI applications run in separate dedicated processes.</li>
      <li>It is the recommended mode for running <code class="language-plaintext highlighter-rouge">mod_wsgi</code>.</li>
    </ul>
  </li>
</ul>

<p>The <a href="https://packages.debian.org/unstable/python/libapache2-mod-wsgi">wsgi module</a> can also be installed in Ubuntu using apt-get:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>libapache2-mod-wsgi
</code></pre></div></div>

<p>Apache automatically enables <code class="language-plaintext highlighter-rouge">mod_wsgi</code> once the module is installed.</p>

<p>We can see that <code class="language-plaintext highlighter-rouge">mod_wsgi</code> is now enabled:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">ls</span> /etc/apache2/mods-enabled
…
wsgi.conf
wsgi.load
…
</code></pre></div></div>

<h2 id="apache-virtualhost">Apache VirtualHost</h2>

<p>At this point, we need to create a new <code class="language-plaintext highlighter-rouge">VirtualHost</code> in Apache (we can use the default site as a template).</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cd</span> /etc/apache2/sites-available
<span class="nv">$ </span><span class="nb">sudo cp </span>000-default.conf juliotrigo.conf
<span class="nv">$ </span>vim juliotrigo.conf
</code></pre></div></div>

<div class="language-apache highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">&lt;</span><span class="nl">VirtualHost</span><span class="sr"> *:80</span><span class="p">&gt;
</span>
  <span class="nc">ServerName</span> juliotrigo.com
  <span class="nc">ServerAlias</span> www.juliotrigo.com

  WSGIScriptAlias / /path/to/juliotrigo.com/juliotrigo/wsgi.py
  WSGIDaemonProcess juliotrigo.com user=myuser group=myuser processes=2 threads=15 python-path=/path/to/juliotrigo.com:/home/myuser/.virtualenvs/juliotrigo/lib/python2.7/site-packages
  WSGIProcessGroup juliotrigo.com

  <span class="p">&lt;</span><span class="nl">Directory</span><span class="sr"> /path/to/juliotrigo.com/juliotrigo</span><span class="p">&gt;
</span>    <span class="p">&lt;</span><span class="nl">Files</span><span class="sr"> wsgi.py</span><span class="p">&gt;
</span>      <span class="nc">Order</span> allow,deny
      <span class="nc">Require</span> <span class="ss">all</span> granted
    <span class="p">&lt;/</span><span class="nl">Files</span><span class="p">&gt;
</span>  <span class="p">&lt;/</span><span class="nl">Directory</span><span class="p">&gt;
</span>
  <span class="nc">Alias</span> /favicon.ico /var/www/juliotrigo/static/img/favicon.ico
  <span class="nc">Alias</span> /static/ /var/www/juliotrigo/static/

  <span class="p">&lt;</span><span class="nl">Directory</span><span class="sr"> /var/www/juliotrigo/static</span><span class="p">&gt;
</span>    <span class="nc">Options</span> -Indexes
    <span class="nc">AllowOverride</span> <span class="ss">None</span>
    <span class="nc">Order</span> deny,allow
    <span class="nc">Allow</span> <span class="ss">from</span> <span class="ss">all</span>
  <span class="p">&lt;/</span><span class="nl">Directory</span><span class="p">&gt;
</span>
<span class="p">&lt;/</span><span class="nl">VirtualHost</span><span class="p">&gt;
</span></code></pre></div></div>

<p>Disable Apache´s default site.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>a2dissite 000-default.conf
Site 000-default disabled.
To activate the new configuration, you need to run:
service apache2 reload
</code></pre></div></div>

<p>Enable our site:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>a2ensite juliotrigo.conf
Enabling site juliotrigo.
To activate the new configuration, you need to run:
service apache2 reload
</code></pre></div></div>

<p>And restart Apache:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo</span> /etc/init.d/apache2 stop
<span class="k">*</span> Stopping web server apache2
<span class="k">*</span>
<span class="nv">$ </span><span class="nb">sudo</span> /etc/init.d/apache2 start
<span class="k">*</span> Starting web server apache2
<span class="k">*</span>
</code></pre></div></div>

<p>In our example, Apache will also serve static files. However, it is recommended to use a separate Web server for that.</p>

<p>We are using mod_wsgi in daemon mode. For that reason, we need to add the <a href="https://code.google.com/archive/p/modwsgi/wikis/ConfigurationDirectives.wiki#WSGIDaemonProcess"><code class="language-plaintext highlighter-rouge">WSGIDaemonProcess</code></a> and <a href="https://code.google.com/archive/p/modwsgi/wikis/ConfigurationDirectives.wiki#WSGIProcessGroup"><code class="language-plaintext highlighter-rouge">WSGIProcessGroup</code></a> directives to create the daemon process, which will run the Django instance in it.</p>

<p>We are also using <a href="https://virtualenv.pypa.io"><strong>virtualenv</strong></a> in our project, that is why we need to add our environment’s site-packages directory to the python path using the <code class="language-plaintext highlighter-rouge">WSGIDaemonProcess</code> directive and supplying the python-path option.</p>

<p>Finally, to say that mod_wsgi can only be used with the version of Python (major.minor) that it was compiled for. If we need to specify a version of Python different than the default version in the system, we can use the <a href="https://modwsgi.readthedocs.io/en/latest/configuration-directives/WSGIPythonHome.html"><code class="language-plaintext highlighter-rouge">WSGIPythonHome</code></a> directive. This is a very interesting and complete <a href="https://groups.google.com/forum/#!topic/modwsgi/Rmgj8IcHC18">article</a> about how to use <code class="language-plaintext highlighter-rouge">WSGIPythonHome</code> / <code class="language-plaintext highlighter-rouge">WSGIPythonPath</code>.</p>

<h2 id="other-ways-of-deploying-django">Other ways of deploying Django</h2>

<p>In a new post, I will talk about how to deploy Django using:</p>
<ul>
  <li>Nginx</li>
  <li>Gunicorn / uWSGI</li>
</ul>

<h2 id="resources">Resources</h2>

<p>Some other resources can be found here:</p>

<p><a href="https://code.google.com/p/modwsgi/wiki/InstallationInstructions">Google code mod_wsgi installation instructions</a></p>

<p><a href="https://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide">Google code mod_wsgi quick configuration guide</a></p>

<p><a href="https://code.google.com/p/modwsgi/wiki/ConfigurationDirectives">Google code mod_wsgi configuration directives</a></p>

<p><a href="https://code.google.com/p/modwsgi/wiki/IntegrationWithDjango">Google code mod_wsgi integration with django</a></p>

<p><a href="https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/modwsgi/">How to use Django with Apache and mod_wsgi</a></p>]]></content><author><name>Julio Trigo</name></author><category term="python" /><category term="django" /><category term="apache" /><category term="WSGI" /><summary type="html"><![CDATA[The aim of this article is to explain how to deploy a Django site with Apache and WSGI on Linux (Ubuntu), considering that neither apache2 nor mod_wsgi have been previously installed in the system. I will use the deployment of my personal website as an example.]]></summary></entry></feed>