<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>frkl - consolidating complexity</title>
    <link>https://frkl.io/</link>
    <description>Recent content on frkl - consolidating complexity</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-US</language>
    <lastBuildDate>Mon, 26 Aug 2019 00:00:00 +0200</lastBuildDate>
    
        <atom:link href="https://frkl.io/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>A (practical) ssh primer</title>
      <link>https://frkl.io/blog/ssh-primer/</link>
      <pubDate>Mon, 26 Aug 2019 00:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/ssh-primer/</guid>
      <description>

&lt;p&gt;This post is the first of a series of articles about basic underlying
principles that are useful to know for the types of devops-y and
sys-admin-y type tasks &lt;a href=&#34;https://freckles.io&#34;&gt;&lt;em&gt;freckles&lt;/em&gt;&lt;/a&gt; usually helps
with. For each topic, I&amp;rsquo;ll write one article that tries to explain the
general principle(s) involved, and a second one outlining how this is
used in the context of &lt;em&gt;freckles&lt;/em&gt;. Feel free to skip that later part
if you don&amp;rsquo;t intend to use &lt;em&gt;freckles&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If in doubt, I&amp;rsquo;ll trade &amp;lsquo;technically correct&amp;rsquo;-ness for ease of
explanation. Treat those articles as a rough overview to get you
started, and consider diving deeper using other resources once you
feel like you have a basic understanding of what is going on.&lt;/p&gt;

&lt;p&gt;This post (and the following ones) assume you have some
understanding of how to use the command-line to do certain tasks
(changing folders, move files, execute applications, &amp;hellip;). I am
pondering whether it&amp;rsquo;s worth to write a primer on command-line usage
too, ping me if that is of interest to you.&lt;/p&gt;

&lt;h2 id=&#34;so-what-is-this-ssh-you-are-talking-about-and-why-should-i-care&#34;&gt;So, what is this &lt;em&gt;ssh&lt;/em&gt; you are talking about and why should I care?&lt;/h2&gt;

&lt;p&gt;As long as you do your work on only your own computer, you won&amp;rsquo;t have
to worry about &lt;em&gt;ssh&lt;/em&gt; at all. But once you want to host some software,
be it &lt;a href=&#34;https://wordpress.org&#34;&gt;Wordpress&lt;/a&gt;,
&lt;a href=&#34;https://nextcloud.com/&#34;&gt;Nextcloud&lt;/a&gt;, or any of the &lt;a href=&#34;https://github.com/Kickball/awesome-selfhosted&#34;&gt;other awesome
packages&lt;/a&gt;
that require an application to run on a remote server constantly &amp;ndash; so
they can serve user requests via the web at any time &amp;ndash; you need some
way to connect to the machine that hosts that software package. To be
able to install, update and generally maintain that service.&lt;/p&gt;

&lt;p&gt;This is where &lt;em&gt;ssh&lt;/em&gt; comes in. &lt;em&gt;ssh&lt;/em&gt; is a sort of &amp;ldquo;Remote Desktop&amp;rdquo; for
your command-line. It runs as a service on the remote machine, and,
depending on how it is configured, lets you login with a username and
password (or private key &amp;ndash; more on that later). Once logged in, you
can operate on the remote machine as you would do locally.&lt;/p&gt;

&lt;p&gt;I won&amp;rsquo;t go into detail on how to setup and configure an ssh service
itself, most cloud providers have ssh setup and running in a basic way
on virtual machines (VMs) you create, and we can just use that for our
purposes here.&lt;/p&gt;

&lt;h2 id=&#34;authentication&#34;&gt;Authentication&lt;/h2&gt;

&lt;p&gt;Authentication is the most important thing we need from &lt;em&gt;ssh&lt;/em&gt;: it is
supposed to only let only known users onto the remote machine. If you
hear of security breaches in the media, often times attackers gain
access to such servers via a mis-configured ssh service.&lt;/p&gt;

&lt;h3 id=&#34;username-password-authentication&#34;&gt;Username/password authentication&lt;/h3&gt;

&lt;p&gt;The most basic way to login via ssh is via a username/password
combination. This is not the most secure way to use &lt;em&gt;ssh&lt;/em&gt;, as usually
a password is not long enough to be considered really secure. But in
some cases it is necessary, most often for the initial configuration
of a server, which, as last step, often involves actually disabling
&lt;em&gt;ssh&lt;/em&gt; password authentication.&lt;/p&gt;

&lt;p&gt;Depending on the cloud provider you choose, you will have gotten a
username and password combination along with the other connection details of
your ssh server. For the purpose of this tutorial, I&amp;rsquo;ll use the
&lt;a href=&#34;https://hetzner.de&#34;&gt;Hetzner cloud&lt;/a&gt; to create virtual machines (mostly
because I find their interface easy enough to use, and they are cheap,
so it&amp;rsquo;s a good fit when you want to try things out). If you
use any of the others (&lt;a href=&#34;https://www.linode.com&#34;&gt;Linode&lt;/a&gt;,
&lt;a href=&#34;https://www.digitalocean.com&#34;&gt;DigitalOcean&lt;/a&gt;, AWS, Google, Azure,&amp;hellip;)
you&amp;rsquo;ll encounter a similar interface and workflow, but it&amp;rsquo;ll differ
enough that you&amp;rsquo;ll probably have to look up other tutorials on the web
for some details.&lt;/p&gt;

&lt;p&gt;So, let&amp;rsquo;s get started. Let&amp;rsquo;s sign up for an account and go the
&lt;a href=&#34;https://console.hetzner.cloud/&#34;&gt;Hetzner cloud management
interface&lt;/a&gt;. There we&amp;rsquo;ll create a new
project (I&amp;rsquo;ll call it &amp;lsquo;Tutorial&amp;rsquo;) and click the &amp;ldquo;Add server&amp;rdquo; button.&lt;/p&gt;

&lt;p&gt;The details you chose on the following screen are not really
important, I&amp;rsquo;ll use a Debian image and the cheapest machine &lt;em&gt;type&lt;/em&gt;
(cx11), and give the machine the name &amp;lsquo;tutorial&amp;rsquo;. All other fields are
either default or blank.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sidenote&lt;/em&gt;: The price of €2.49 is per month, if the server only runs
for part of a month, you&amp;rsquo;ll only have to pay the hourly rate
(€0.004/hour).&lt;/p&gt;

&lt;p&gt;Once we &amp;lsquo;buy&amp;rsquo; our server, we wait until it is provisioned by
Hetzner. This usually takes 10 to 20 seconds. Hetzner will send you an
email with the connection details.&lt;/p&gt;

&lt;p&gt;We need the IPv4 address, the username, and the password to be able to
connect via ssh:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh &amp;lt;username&amp;gt;@&amp;lt;ipv4&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The IPv4 address is necessary for the underlying technologies to route
our commands to the right server. In my case, the IP address I
received was &amp;lsquo;116.203.23.175&amp;rsquo;, and the username &amp;lsquo;root&amp;rsquo; (which is the
main &amp;lsquo;admin&amp;rsquo; user on Linux systems).&lt;/p&gt;

&lt;p&gt;So, here&amp;rsquo;s what I do on my terminal:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ssh root@116.203.23.175
The authenticity of host &#39;116.203.23.175 (116.203.23.175)&#39; can&#39;t be established.
ECDSA key fingerprint is SHA256:RpD/BudrVmHy0mri4aFK493JSmIul0pRRrHJ2Rz9Log.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added &#39;116.203.23.175&#39; (ECDSA) to the list of known hosts.
root@116.203.23.175&#39;s password: xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &amp;lsquo;authenticity&amp;rsquo; message will be displayed on your first connection
attempt, and can be used to verify that you are connecting to the
server you intend to connect to (and there is no man-in-the-middle
attack happening). How to do that is an advanced topic,
and in practice not many people do that when creating new VMs like we
just did.&lt;/p&gt;

&lt;p&gt;Once I entered the password from the email I received, I&amp;rsquo;m logged
in. The Hetzner VMs are configured in a way that when logging in the
first time, the user has to set a new password for the &amp;lsquo;root&amp;rsquo;
user. Which is a good practice, because passwords sent via email can
not be considered secure. Here&amp;rsquo;s how that looked for me:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;You are required to change your password immediately (root enforced)
Linux tutorial 4.9.0-9-amd64 #1 SMP Debian 4.9.168-1+deb9u2 (2019-05-13) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jun 22 12:18:36 2019 from 89.158.123.195
Changing password for root.
(current) UNIX password: xxx
Enter new UNIX password: yyy
Retype new UNIX password: yyy
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that&amp;rsquo;s basically all there is to it. Except, as I&amp;rsquo;ve mentioned,
that using username/password authentication is not really the
best/safest way to use &lt;em&gt;ssh&lt;/em&gt;. So, let&amp;rsquo;s look at:&lt;/p&gt;

&lt;h3 id=&#34;private-key-authentication&#34;&gt;Private key authentication&lt;/h3&gt;

&lt;p&gt;You can think of a &amp;lsquo;&lt;em&gt;private key&lt;/em&gt;&amp;rsquo; (also called &lt;em&gt;ssh&lt;/em&gt; key in this
context) as a really long (and therefor really secure) password, one
that you don&amp;rsquo;t want to type in every time (and you couldn&amp;rsquo;t really
remember it anyway). That is why it is stored in a file on your local
machine (usually at &lt;code&gt;$HOME/.ssh/id_rsa&lt;/code&gt; &amp;ndash; &lt;code&gt;$HOME&lt;/code&gt; is a variable
that points to the root folder for your user, usually the full path is:
&lt;code&gt;/home/&amp;lt;username&amp;gt;/.ssh/id_rsa&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For security reasons, most of the times that really
long password is encrypted with another, shorter password (one that
you actually can, and should, remember). This encryption protects
against users on the same computer just copying the &amp;lsquo;password/private
key-file&amp;rsquo; and using it to impersonate you. But it is also an
inconvenience, because it means that everytime you want to use it, you
have to enter your (short) password, to decrypt the private key.&lt;/p&gt;

&lt;p&gt;Now, how do we create the private key? There&amp;rsquo;s a tool for that on
almost all Linux (and Mac OS X) machines: &lt;code&gt;ssh-keygen&lt;/code&gt;. It supports
different options, but until you know better, I&amp;rsquo;d recommend just using
one of the recommended parameters that is compatible with most systems
and which will result in a reasonable secure setup:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ssh-keygen -t rsa -b 4096

Generating public/private rsa key pair.
Enter file in which to save the key (/home/markus/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/markus/.ssh/id_rsa.
Your public key has been saved in /home/markus/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:rzDEUqBmzKqYkhjullfnhFRXYdJeP4nP6Ml2zOlpS1c markus@t440p
The key&#39;s randomart image is:
+---[RSA 4096]----+
|    .    .o+.    |
| o . . . .o. .   |
|  *   o . . . o .|
| +   +     . . + |
|o   o + S     + E|
|=+   = o .   . o.|
|B.. . *   . o +.o|
|oo .   + .   =.*o|
|...     .   . ++.|
+----[SHA256]-----+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Sidenote&lt;/em&gt;: if you are ok with a very small risk of incompatibilites,
it is recommended to use the &amp;lsquo;Ed25519&amp;rsquo; algorithm instead of &amp;lsquo;rsa&amp;rsquo;
(&lt;code&gt;-t ed25519&lt;/code&gt; instead of &lt;code&gt;-t rsa&lt;/code&gt;). Check the internet (like
&lt;a href=&#34;https://medium.com/risan/upgrade-your-ssh-key-to-ed25519-c6e8d60d3c54&#34;&gt;here&lt;/a&gt;)
for more information. Using &amp;lsquo;rsa&amp;rsquo; with a keysize of 4096 is a good
enough choice though.&lt;/p&gt;

&lt;p&gt;Once that is done, the &amp;lsquo;ssh-keygen&amp;rsquo; command will have created two&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$HOME/.ssh/id_rsa&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$HOME/.ssh/id_rsa.pub&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one is our private key, encrypted with the password we
provided. This file is important, and should be kept secure. Never
send your private key file over a network, or let anybody access it.&lt;/p&gt;

&lt;p&gt;The second one is a file that contains a sort of unique
&amp;lsquo;fingerprint&amp;rsquo; of our private key. This file does not need to be kept
secure. In fact, often you&amp;rsquo;ll be asked to provide the
content of this file (e.g. on GitHub or similar services).&lt;/p&gt;

&lt;p&gt;Why do I need this &amp;lsquo;fingerprint&amp;rsquo;? Good question, and if you understand
the answer you understand the basic principle of why ssh private key
authentication is done the way it is done.&lt;/p&gt;

&lt;p&gt;I won&amp;rsquo;t go into detail about how exactly this works under the hood
(not that I actually know&amp;hellip;), but (thankfully) that is not necessary
to use any of this. The main thing you need to know is that for the
process of getting a sorta &amp;lsquo;fresh&amp;rsquo; fingerprint you need the private
key (you can&amp;rsquo;t just copy the fingerprint itself), and every such
fingerprint is, for all practical purposes, unique amongst all of the
fingerprints of all ssh keys in existence.&lt;/p&gt;

&lt;p&gt;To be able to assert that without a doubt is very useful, because now,
if you are a remote server with only knowledge of the fingerprint
(which is usually called &amp;lsquo;&lt;em&gt;public key&lt;/em&gt;&amp;rsquo;), you can ask the owner of the
private key to give you a fingerprint (in a secure way), compare that
with what you have in your records, and if there is a match you can be
certain whoever asked you to let them in is in possession of the
private key that belongs to the fingerprint.&lt;/p&gt;

&lt;p&gt;The alternative would have been for you have the content of the
private key in your records. And you compare that to the private key
somebody who wants to login presents. This would have been bad for
several reasons though, the worst being that the private key is now
stored on the remote server, and anybody who can access that (via
vulnerabilities, or maybe just because they are an admin user on that
server) can now impersonate you on other services where you use the
same key. Which would mean we would have to use a different private
key for every server we want to connect to. Because we only use the
fingerprint, and it is not possible to &amp;lsquo;fake&amp;rsquo; the fingerprint-taking
process without the private key (this is the crux, really), we can
distribute our fingerprint to as many services and servers as we want,
without having to worry about anybody we give it to will be able to
impersonate us.&lt;/p&gt;

&lt;p&gt;Now, let&amp;rsquo;s use our key!&lt;/p&gt;

&lt;p&gt;First, let&amp;rsquo;s add our public ssh key to the VM we created earlier,
manually. Then we&amp;rsquo;ll create a new VM, using ssh key authentication
from the start (the recommended way).&lt;/p&gt;

&lt;p&gt;To add our newly created key, we need to get the content of the public
key (&amp;lsquo;fingerprint&amp;rsquo;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ echo $HOME/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8TbDtJ4P3aF8eM0rAIrSrxea53p3qisN2jbvzW1rKGbaSJXKFCprVa05gFGUBeBZq2coHhIEOX3j+h+oNsWVWPdfY/mLt1a5uvQ+skY1j7Roc74xjNw0HzW71sTesodGXdXOACU4ins9FHUCkDdDW62sSARRTMaBksLvWMvzhR3dRiA3KgUTy8R2ObJITEqh4Ztbkfwzi+ntOOLJOJ+zediTsYlsT5ZPDlRcJamU6fV8XqinmuppEtBtuM8qd3cn42Oh+00AxyebgY0wyE9EJ9jr5S+cHICRoOxQGWagGBKhh8JAcFx3RwbSMY1+rk5lDIXavW+w6HA5WAntNZzLL markus@frkl.io
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To add that key to the &amp;lsquo;root&amp;rsquo; user account of our VM, we need to login
(using the password method), and then copy and paste our public key
into the file &lt;code&gt;$HOME/.ssh/authorized_keys&lt;/code&gt; on the remote
machine. Alternatively we could use the &amp;lsquo;ssh-copy-id&amp;rsquo; command, which
will read thee public ssh key, login to the remote server, and copy
the public-key-content into the appropriate place:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;ssh-copy-id root@116.203.23.175

/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@116.203.23.175 password:

Number of key(s) added: 1

Now try logging into the machine, with:   &amp;quot;ssh root@116.203.23.175&#39;&amp;quot;
and check to make sure that only the key(s) you wanted were added.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After that we can try to login again, and this time around we should not be asked
for the root password of the server, but for the password of our ssh
key:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ssh root@116.203.23.175
root@116.203.23.175&#39;s password: &amp;lt;root_password&amp;gt;
Linux tutorial 4.9.0-9-amd64 #1 SMP Debian 4.9.168-1+deb9u2 (2019-05-13) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jun 22 14:17:19 2019 from 89.158.123.195

root@tutorial:~# echo &#39;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8TbDtJ4P3aF8eM0rAIrSrxea53p3qisN2jbvzW1rKGbaSJXKFCprVa05gFGUBeBZq2coHhIEOX3j+h+oNsWVWPdfY/mLt1a5uvQ+skY1j7Roc74xjNw0HzW71sTesodGXdXOACU4ins9FHUCkDdDW62sSARRTMaBksLvWMvzhR3dRiA3KgUTy8R2ObJITEqh4Ztbkfwzi+ntOOLJOJ+zediTsYlsT5ZPDlRcJamU6fV8XqinmuppEtBtuM8qd3cn42Oh+00AxyebgY0wyE9EJ9jr5S+cHICRoOxQGWagGBKhh8JAcFx3RwbSMY1+rk5lDIXavW+w6HA5WAntNZzLL markus@frkl.io&#39; &amp;gt;&amp;gt; $HOME/.ssh/authorized_keys

root@tutorial:~# exit
logout
Connection to 116.203.23.175 closed.

vagrant@debian-testing:~$ ssh root@116.203.23.175
Enter passphrase for key &#39;/home/vagrant/.ssh/id_rsa&#39;:
Linux tutorial 4.9.0-9-amd64 #1 SMP Debian 4.9.168-1+deb9u2 (2019-05-13) x86_64
...
...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The one thing to note here is that the &lt;code&gt;authorized_keys&lt;/code&gt; file
(always in &lt;code&gt;$HOME/.ssh/authorized_keys&lt;/code&gt;) is the servers record for
which private key &amp;lsquo;fingerprints&amp;rsquo; to allow access for the particular
user that tries to login. Every line in it denotes one public key
(&amp;lsquo;fingerprint&amp;rsquo;).&lt;/p&gt;

&lt;p&gt;We can let Hetzner do the same thing for us, by registering our public
ssh key with them. Go to the Hetzner cloud &amp;lsquo;Access&amp;rsquo; page of our project (left
side, key symbol), and click the &amp;lsquo;Add ssh key&amp;rsquo; button.&lt;/p&gt;

&lt;p&gt;Copy and paste your public key (the line that starts with
&amp;lsquo;ssh-rsa&amp;hellip;.&amp;rsquo;) into the approriate text field, and give your key a
name (&amp;lsquo;tutorial-key&amp;rsquo;).&lt;/p&gt;

&lt;p&gt;Now, the next time you create a machine, the puchase page lets you
select from your registered ssh keys. Select the one you want to be
included, and after the server is up you should be able to use it to
login the same way we did when we added the key to &amp;lsquo;authorized_keys&amp;rsquo; manually.&lt;/p&gt;

&lt;h3 id=&#34;password-protected-private-keys-or-not&#34;&gt;Password protected private keys, or not?&lt;/h3&gt;

&lt;p&gt;As I&amp;rsquo;ve mentioned above, usually we protect our private key with a
password, but sometimes we don&amp;rsquo;t. When should we do what? Well, rule
of thumb: use a password.&lt;/p&gt;

&lt;p&gt;Once you start managing servers, it&amp;rsquo;s getting a bit more difficult
though. The issues start once we do &amp;lsquo;automation&amp;rsquo;. &amp;lsquo;Automation&amp;rsquo; is
everything we want our computers to do automatically, without us
having to do anything, except for an initial manual setup of the
automation process (and even that we sometimes automate &amp;ndash; but that is
a different topic).&lt;/p&gt;

&lt;p&gt;&amp;lsquo;Automation&amp;rsquo; means we should not have to intervene at all. One example
would be a task that gets done every day at the same time (often via
&lt;a href=&#34;https://www.ostechnix.com/a-beginners-guide-to-cron-jobs/&#34;&gt;&amp;lsquo;cron&amp;rsquo;
jobs&lt;/a&gt;). Or
a setup task you want to be kicked off every time you commit to a git
repository.&lt;/p&gt;

&lt;p&gt;If that task involves your private ssh key in some way (for example:
build the package, login to a server via ssh, then install the
package), you somehow have to &amp;lsquo;unlock&amp;rsquo; your private key for every one
of those tasks. You could, of course, just store the password to the
private key on the same machine as your private key. But that would
defeat the purpose, and would be pretty much as secure as just using no
password on your private key at all. Because, if an attacker can read
you (encrypted) private key, they also have access to read your
password file&amp;hellip;&lt;/p&gt;

&lt;p&gt;There &lt;em&gt;are&lt;/em&gt; ways to protect your private key in scenarios like this,
but almost none of them are flawless, and none of them are
straight-forward. You having to manually enter a password is really
the best in terms of security. And the worst in terms of
convenience. This is why there are certain situations where people
decide to not secure the private key with a password, and accept
the security implications that come with this decision.&lt;/p&gt;

&lt;p&gt;There is not much advice I can give on a primer like this, I&amp;rsquo;d just
recommend that whenever you get stuck trying to automate something,
and passwords are involved, try to search the internet for people with
a similar problems and technologies, and check whether there seems to
be a sort of consensus (well, as close an approximation to &amp;lsquo;consensus&amp;rsquo;
there exists on the internet, anyway) &amp;lsquo;best-practice&amp;rsquo; for your type of
situation.&lt;/p&gt;

&lt;h3 id=&#34;the-ssh-agent&#34;&gt;The &lt;code&gt;ssh-agent&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;On your local machine, there is one remedy for the inconvenience of
having to enter the password to your ssh key every time you want to
use it: &lt;a href=&#34;https://www.ssh.com/ssh/agent&#34;&gt;&lt;code&gt;ssh-agent&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It comes with a minor impact on security, but my feeling is that
most people accept that for the huge boost in convenience it brings.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh-agent&lt;/code&gt; is a little daemon (a program that runs in the
background) which can store passwords for ssh keys in a secure
way. That means, you have to enter the password once, the first time
you use a ssh key in a session, and after that the &lt;code&gt;ssh-agent&lt;/code&gt; will
intercept any access requests for the ssh key in question, and
will provide the decrypted key to whatever program requested it.&lt;/p&gt;

&lt;p&gt;Most people (and Linux distributions) start &lt;code&gt;ssh-agent&lt;/code&gt;
automatically in some way when the user logs in. It is hard to give general
advice on how to use it because of the different ways this is
done. So I&amp;rsquo;ll only outline how it works in principle, below.&lt;/p&gt;

&lt;p&gt;If you type &lt;code&gt;ssh-agent&lt;/code&gt; in your terminal, you&amp;rsquo;ll see something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-eq76YPuBvNU8/agent.12962; export SSH_AUTH_SOCK;
SSH_AGENT_PID=12963; export SSH_AGENT_PID;
echo Agent pid 12963;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This does 2 things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;start the &lt;code&gt;ssh-daemon&lt;/code&gt; (type &lt;code&gt;ps axu|grep ssh-agent&lt;/code&gt; to confirm)&lt;/li&gt;
&lt;li&gt;print out details that are needed to connect to the running
ssh-agent daemon&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you start the agent several times, you&amp;rsquo;ll notice that the printed
  details are always slightly different. The reason for this is that
  you can have several ssh-agents processes running at the same time,
  and each of them can store different (or the same) ssh keys. In most
  cases we only want one of those agents running though.&lt;/p&gt;

&lt;p&gt;Now, what are those &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; and &lt;code&gt;SSH_AGENT_PID&lt;/code&gt; variables?
Those need to be present in the environment of a process that wants to
use the ssh-agent so the process knows how to connect to the
agent. Reading the content of the  &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; variable is how
that is done. In our case, an application would read that value, and
would use the &lt;code&gt;/tmp/ssh-eq76YPuBvNU8/agent.12962&lt;/code&gt; path (which is not a
&amp;lsquo;normal&amp;rsquo; file, but a &lt;a href=&#34;https://en.wikipedia.org/wiki/Unix_domain_socket&#34;&gt;unix
socket&lt;/a&gt;) to &amp;lsquo;talk&amp;rsquo;
to our ssh-agent.&lt;/p&gt;

&lt;p&gt;So, what the output of our &lt;code&gt;ssh-agent&lt;/code&gt; command is telling us: &amp;lsquo;those
are my connection details, please put them in your environment if you
want to use me&amp;rsquo; (it&amp;rsquo;can&amp;rsquo;t do it itself for &amp;hellip; reasons). So, we can
either do this now, manually (by copying and pasting the two relevant
lines of the output):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ SSH_AUTH_SOCK=/tmp/ssh-eq76YPuBvNU8/agent.12962; export SSH_AUTH_SOCK;
$ SSH_AGENT_PID=12963; export SSH_AGENT_PID;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or, we use the
&lt;a href=&#34;https://www.tutorialspoint.com/unix_commands/eval.htm&#34;&gt;&lt;code&gt;eval&lt;/code&gt;&lt;/a&gt;
command to do it for us (which is what the ssh-agent output is
designed for), by wrapping the &lt;code&gt;eval&lt;/code&gt; around our &lt;code&gt;ssh-agent&lt;/code&gt;
command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ eval $(ssh-agent)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Basically, this executes ssh-agent, then it executes the output of the
ssh-agent execution. We can confirm this worked by checking our
processes for the &amp;lsquo;ssh-agent&amp;rsquo; process, and the contents of our &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; and
&lt;code&gt;SSH_AGENT_PID&lt;/code&gt; environment variables:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ps axu|grep ssh-agent
markus   24648  0.0  0.0   5164   336 ?        Ss   13:59   0:00 ssh-agent
markus   25117  0.0  0.0   6604   728 pts/3    S+   13:59   0:00
grep ssh-agent

$ echo $SSH_AUTH_SOCK
/tmp/ssh-i1u4UBNrqPQZ/agent.24647

$ echo $SSH_AGENT_PID
24648
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Right. Now we have &amp;lsquo;ssh-agent&amp;rsquo; running. What&amp;rsquo;s next?&lt;/p&gt;

&lt;p&gt;We need to register the ssh keys we intend to use with it! In most
cases, there exists only the default key: &lt;code&gt;$HOME/.ssh/id_rsa&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Because this is the default, we don&amp;rsquo;t need to provide a path to the
key, we only need to call:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ssh-add
Enter passphrase for /home/markus/.ssh/id_rsa:
Identity added: /home/markus/.ssh/id_rsa (/home/markus/.ssh/id_rsa)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once that is done, every ssh connection that uses that key will use
the stored key in ssh-agent, and we&amp;rsquo;ll never have to use provide the
ssh key password manually again.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>&#39;Dockerfiles&#39; for LXD</title>
      <link>https://frkl.io/blog/dockerfiles-for-lxd/</link>
      <pubDate>Sat, 10 Aug 2019 00:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/dockerfiles-for-lxd/</guid>
      <description>

&lt;h2 id=&#34;tldr&#34;&gt;tldr&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://freckles.io&#34;&gt;&lt;em&gt;freckles&lt;/em&gt;&lt;/a&gt; can be used as a generic, composable
&amp;lsquo;Dockerfile&amp;rsquo; replacement for LXD. To try it out, on a system that has
&lt;em&gt;freckles&lt;/em&gt; and LXD installed and working, put the following content
into a file &lt;code&gt;&#39;example-lxd.frecklet&lt;/code&gt;&amp;lsquo;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- nginx-service
- nginx-vhost-from-folder:
    document_root: /var/www/html
    default_server: true
    use_https: false
- file-with-content:
    owner: www-data
    path: /var/www/html/index.html
    content: |
      &amp;lt;h1&amp;gt;&amp;lt;i&amp;gt;freckles&amp;lt;/i&amp;gt; says &amp;quot;Hello World&amp;quot;, from {{:: from ::}}!&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will act as our &amp;lsquo;Dockerfile&amp;rsquo; and describes how to install and
configure Nginx to serve a static webpage. To create an LXD image from
it, execute:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute lxd-image-from-frecklet-file \
     --install-packer \
     --source-image images:debian/10 \
     --image-name freckles-image \
     --frecklet-path $(pwd)/example-lxd.frecklet \
     --frecklet-vars &#39;{&amp;quot;from&amp;quot;: &amp;quot;my first image&amp;quot;}&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once that has finished, create a container from the new
&amp;lsquo;freckles-image&amp;rsquo; image:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ lxc launch freckles-image freckles-test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To test whether the Nginx service that runs in the container works, issue:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ curl http://&amp;lt;container_ip&amp;gt;
&amp;lt;h1&amp;gt;&amp;lt;i&amp;gt;freckles&amp;lt;/i&amp;gt; says &amp;quot;Hello World&amp;quot;, from my first image!&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;long-ish-preamble&#34;&gt;Long-ish preamble&lt;/h2&gt;

&lt;p&gt;I think Dockerfiles played a fairly big part in Dockers success and
adoption early on. They are simple to read/understand, flexible enough to
be useful beyond basic tasks, and composable (if you squint your eyes
a bit and look at &amp;lsquo;inheriting from another Docker image&amp;rsquo; as
composition).&lt;/p&gt;

&lt;p&gt;Of course, there are other factors for Dockers success, being at the
right time at the right place (a.k.a. luck) among them, but
Dockerfiles are certainly important. Docker containers are usually
considered to be &amp;lsquo;application containers&amp;rsquo;, and part of a
microservice-type architecture. In practices, that is (and probably
never was) 100% true, there are a lot of people trying to force Docker
into something else, for example coming up with &amp;lsquo;init-systems&amp;rsquo; for
Docker, trying to run webapps incl. Database and Memcache and whatever
else in a single container. Think of that what you will, it&amp;rsquo;s still a
testament for Dockers success, and the flexibility of Dockerfiles,
because they actually allow for all this to be built.&lt;/p&gt;

&lt;p&gt;Now, if we just accept the premise there are cases where its
advantageous to have multiple services on the same host without the
overhead of a virtual network connecting all of them (and we could
certainly argue when that makes and doesn&amp;rsquo;t make sense), we&amp;rsquo;ll sooner
or later stumble upon LXD (I&amp;rsquo;ll ignore the more low-level LXC, but I
acknowledge that sometimes it&amp;rsquo;d be a better fit).&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://linuxcontainers.org/lxd/introduction/&#34;&gt;LXD&lt;/a&gt; is a so-called
&amp;lsquo;system container manager&amp;rsquo; (as opposed to &amp;lsquo;application container&amp;rsquo;),
which means it &amp;lsquo;contains&amp;rsquo; whole operating systems, including a
&amp;lsquo;normal&amp;rsquo; init system. An LXD container behaves like a physical or
virtual machine, except for some permission-related things, but
without much overhead (like &amp;lsquo;real&amp;rsquo; VMs, for example).&lt;/p&gt;

&lt;p&gt;LXD does not have an equivalent to a Dockerfile though (fairly or
unfairly ignoring &amp;lsquo;cloud-init&amp;rsquo; in this instance &amp;ndash; this is a topic for
a whole other blog post). One reason for this is that it&amp;rsquo;s not
&lt;em&gt;really&lt;/em&gt; necessary. Since an LXD container behaves like a normal
physical or virtual machine, we can use the same tooling to install
applications, and generally get a container into the state we want it
to be. And for the case where sysadmin/devops-professionals do the
state-making, that is fine, they know what to do, and how to do it in
an automated way. Using tools like Ansible, Puppet. Or maybe Packer,
Terraform, etc.&lt;/p&gt;

&lt;p&gt;The one advantage a &amp;lsquo;Dockerfile for LXD&amp;rsquo; would have in that situation
is to bring easy reproducability, re-usability, and just general
&amp;lsquo;orderlyness&amp;rsquo; to LXD for people who don&amp;rsquo;t have to deal with those
things usually. In the same way Dockerfiles brought those things along
with Docker. All you need is a single text file, and you&amp;rsquo;ll be able to
replicate and costumize a Docker image. I think we can&amp;rsquo;t overestimate
the effect of a technology that allows people who know what they are
doing (those who create Dockerfiles) to share what they are doing
(Dockerfiles) with people who wouldn&amp;rsquo;t have known how to do
that particular thing (at least without spending a few hours on
Stackoverflow) or can&amp;rsquo;t be bothered, and who now can just re-use that
particular thing.&lt;/p&gt;

&lt;p&gt;A thing which, by the way, now only has to be created once, and which
then can be continuously improved upon by a community of people (who
ideally know what they are doing). It&amp;rsquo;s like using a specialized
library in any programming language, it allows you to focus on your
core problem as an application developer, without too much distraction
on those tangential details you&amp;rsquo;d have to worry about otherwise. It&amp;rsquo;s
really not that deep of a problem, everything considered. But it&amp;rsquo;s
wide-spread, and prevalent to the point that we often don&amp;rsquo;t even see
and recognize it in our daily (working) life, which means we are not
taking advantage of the already existing solutions for such a problem.&lt;/p&gt;

&lt;p&gt;This is, incidentally, exactly what &lt;a href=&#34;https://freckles.io&#34;&gt;freckles&lt;/a&gt;
tries to solve too, just in a more generic way than a
Dockerfile does. Allow for re-usable recipes to bring computational
environments into a certain state, technolgy- and stack-independent.&lt;/p&gt;

&lt;p&gt;Which, finally, brings me to the topic of this post: using
&lt;a href=&#34;https://freckles.io/doc/frecklets&#34;&gt;&lt;em&gt;frecklets&lt;/em&gt;&lt;/a&gt; as sort of re-usable
&amp;lsquo;Dockerfile-replacements&amp;rsquo;. In the context of LXD. Of course, since
they are re-usable, you can use the same &lt;em&gt;frecklet&lt;/em&gt; you use in LXD for
Docker too (with some caveats), or, to provision a remote server (as
I&amp;rsquo;ll show at the end of this post).&lt;/p&gt;

&lt;h2 id=&#34;using-freckles-with-lxd&#34;&gt;Using &lt;em&gt;freckles&lt;/em&gt; with LXD&lt;/h2&gt;

&lt;p&gt;There are two separate areas where we can choose to use &lt;em&gt;freckles&lt;/em&gt; in
combination with LXD:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;describing the content/state of the images&lt;/li&gt;
&lt;li&gt;building the actual LXD images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, we can use &lt;em&gt;freckles&lt;/em&gt; to install and configure LXD:&lt;/p&gt;

&lt;h3 id=&#34;optional-using-freckles-to-install-lxd&#34;&gt;Optional: using &lt;em&gt;freckles&lt;/em&gt; to install LXD&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: the following does not setup internet connectivity for
containers who are connected to the newly created bridge
&amp;lsquo;lxbr0&amp;rsquo;. This has to be done manually (for now), e.g. by doing
&lt;code&gt;iptables -t nat -A POSTROUTING -s &amp;lt;bridge_subnet&amp;gt;.0/24 -o eth0 -j
MASQUERADE&lt;/code&gt;. This will be done automatically sometime in the future, hopefully.&lt;/p&gt;

&lt;p&gt;For this, we can use the
&lt;a href=&#34;https://freckles.io/frecklets/default/virtualization/lxd-service&#34;&gt;&lt;code&gt;lxd-service&lt;/code&gt;&lt;/a&gt;
frecklet:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute lxd-service --user markus
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Under the hood, this uses the
&lt;a href=&#34;https://github.com/juju4/ansible-lxd&#34;&gt;juju4.lxd&lt;/a&gt; Ansible role to
install LXD on a Ubuntu or RedHat-based Linux system. Other
distributions might work, but are not tested. Also, note the &lt;code&gt;--user
markus&lt;/code&gt; command-line argument. This lets you specify one or several
users who&amp;rsquo;ll have permissions to use the LXD service on this
host. After running this, you&amp;rsquo;ll have to either log-out of your
current session and log-in again, or execute &lt;code&gt;newgrp lxd&lt;/code&gt; to take
advantage of this permission.&lt;/p&gt;

&lt;p&gt;It is possible to adjust some parameters related to your LXD setup
with this &lt;em&gt;frecklet&lt;/em&gt; (like for example network addresses or storage
settings), but this is out of scope in this context.&lt;/p&gt;

&lt;h3 id=&#34;describing-the-lxd-image-contents&#34;&gt;Describing the LXD-image contents&lt;/h3&gt;

&lt;p&gt;We&amp;rsquo;ll be writing a relatively simple
&lt;a href=&#34;https://freckles.io/doc/frecklets&#34;&gt;&lt;em&gt;frecklet&lt;/em&gt;&lt;/a&gt;, not different at all
to anything we&amp;rsquo;d write for a different target type (e.g. a remote
server). For more details on how to all this works, and how you can
write your own, please check the &lt;a href=&#34;https://freckles.io/doc/getting_started&#34;&gt;&lt;em&gt;freckles&lt;/em&gt; getting started
guide&lt;/a&gt; and the &lt;a href=&#34;https://freckles.io/doc/frecklets&#34;&gt;other
frecklet-related documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For our example, lets install the Nginx webserver and configure it to
host a single, static html site (which we also create dynamically).&lt;/p&gt;

&lt;p&gt;As this is a relatively &amp;lsquo;normal&amp;rsquo; thing to do, there are already
pre-made &lt;em&gt;frecklets&lt;/em&gt; that can help us implement the required steps,
which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;install the Nginx packages and enable/start the service (&lt;a href=&#34;https://freckles.io/frecklets/default/service/nginx-service&#34;&gt;&lt;code&gt;nginx-service&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;create a configuration for our vhost (&lt;a href=&#34;https://freckles.io/frecklets/default/service/nginx-vhost-from-folder&#34;&gt;&lt;code&gt;nginx-vhost-from-folder&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;create our html file (&lt;a href=&#34;https://freckles.io/frecklets/default/filesystem/file-with-content&#34;&gt;&lt;code&gt;file-with-content&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;rsquo;s how that looks as a &lt;em&gt;frecklet&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- nginx-service
- nginx-vhost-from-folder:
    document_root: /var/www/html
    default_server: true
    use_https: false
- file-with-content:
    owner: www-data
    path: /var/www/html/index.html
    content: |
      &amp;lt;h1&amp;gt;&amp;lt;i&amp;gt;freckles&amp;lt;/i&amp;gt; says &amp;quot;Hello World&amp;quot;, from {{:: from ::}}!&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note the &lt;code&gt;{{:: from ::}}&lt;/code&gt; template string in our &lt;em&gt;frecklet&lt;/em&gt;
code: this lets us customize the generated html for every LXD image
(if we chose to do so).&lt;/p&gt;

&lt;p&gt;To test, lets launch an LXC ocntainer and provision it with our new
&lt;em&gt;frecklet&lt;/em&gt;. We could do this with a simple &lt;code&gt;lxc launch ...&lt;/code&gt; command,
but while we&amp;rsquo;re at it let&amp;rsquo;s use &lt;em&gt;freckles&lt;/em&gt; for this too. In an
interactive session that doesn&amp;rsquo;t make much sense, since it&amp;rsquo;s also just
one command, and comes with a bit of overhead. But it&amp;rsquo;s a good
opportunity to show how one would do that if launching an LXD
container was part of a provisioning pipeline. So, here goes:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute lxd-container-running --image-name &#39;debian/10&#39; \
     --image-server https://images.linuxcontainers.org \
     --name &#39;freckles-test&#39; \
     --register-addresses freckles_container_ip

╭╼ starting run
│  ├╼ running frecklet: lxd-container-running (on: localhost)
│  │  ├╼ starting Ansible run
│  │  │  ├╼ create/launch container &#39;freckles-test&#39;
│  │  │  │  ╰╼ ok
│  │  │  ╰╼ ok
│  │  ╰╼ ok
│  ╰╼ ok
╰╼ ok

Result:

    freckles_container_ip:
      eth0:
      - 10.10.10.42
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, we provided the optional &lt;code&gt;--register-addresses&lt;/code&gt;
command-line argument. That prompts &lt;em&gt;freckles&lt;/em&gt; to register the
(network) details of our newly created container into a variable,
which makes it easier for us to connect to it later. Alternatively,
you can get the ip address with a simple &lt;code&gt;lxc list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that our container is running, we can provision it using our
&lt;em&gt;frecklet&lt;/em&gt; from above. We&amp;rsquo;ll save the content string as
&lt;code&gt;example-lxd.frecklet&lt;/code&gt;, then issue:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute --target lxd::freckles-test example-lxd.frecklet --from &#39;a test run&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The crucial thing is the &lt;code&gt;--target lxd::&amp;lt;container_name&amp;gt;&lt;/code&gt; part. It
tells &lt;em&gt;freckles&lt;/em&gt; to not connect via &lt;em&gt;ssh&lt;/em&gt;, but directly via &amp;lsquo;lxd&amp;rsquo;.&lt;/p&gt;

&lt;p&gt;This will take a minute or two, as there is some bootstrapping to be
done in addition to installing Nginx. Once the process is finished,
you should be able to point your browser to the IP address displayed
in the run before this, and see the message &amp;ldquo;freckles says &amp;ldquo;Hello World&amp;rdquo;, from a test run!&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Sweet, now we have everything we need to make that into an LXD
container image&amp;hellip;&lt;/p&gt;

&lt;h3 id=&#34;building-an-lxd-image&#34;&gt;Building an LXD image&lt;/h3&gt;

&lt;p&gt;While it&amp;rsquo;s possible to create an LXD image from scratch using &lt;em&gt;freckles&lt;/em&gt;, for
example by capturing the steps from &lt;a href=&#34;https://tutorials.ubuntu.com/tutorial/create-custom-lxd-images#0&#34;&gt;this
tutorial&lt;/a&gt;
into a &lt;em&gt;frecklet&lt;/em&gt;, we won&amp;rsquo;t do that here. We are going to be cheating a bit, and use
&lt;a href=&#34;https://www.packer.io&#34;&gt;Packer&lt;/a&gt; instead, since that offers the
same functionality (and more), with less hassle.&lt;/p&gt;

&lt;p&gt;As we already have our &lt;code&gt;example-lxd.frecklet&lt;/code&gt; file, all we need to
do is provide it&amp;rsquo;s full path in the following command:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute container-image-from-frecklet-file \
     --install-packer \
     --image-type lxd \
     --source-image images:debian/10 \
     --image-name freckles-image \
     --frecklet-path $(pwd)/example-lxd.frecklet \
     --frecklet-vars &#39;{&amp;quot;from&amp;quot;: &amp;quot;my first image&amp;quot;}&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s look at that command in detail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://freckles.io/frecklets/default/virtualization/container-image-from-frecklet-file&#34;&gt;&lt;code&gt;container-image-from-frecklet-file&lt;/code&gt;&lt;/a&gt;: the name of &lt;a href=&#34;https://freckles.io/frecklets/default/virtualization/container-image-from-frecklet-file&#34;&gt;the
frecklet&lt;/a&gt;
we want to execute (we could have also used the wrapper &lt;em&gt;frecklet&lt;/em&gt; &lt;a href=&#34;https://freckles.io/frecklets/default/virtualization/lxd-image-from-frecklet-file&#34;&gt;&lt;code&gt;lxd-image-from-frecklet-file&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--install-packer&lt;/code&gt;: we make sure that the
&lt;a href=&#34;https://www.packer.io&#34;&gt;Packer&lt;/a&gt; executable is available on our
system (using the
&lt;a href=&#34;https://freckles.io/frecklets/default/devops/packer-installed&#34;&gt;&lt;code&gt;packer-installed&lt;/code&gt;&lt;/a&gt;
&lt;em&gt;frecklet&lt;/em&gt; under the hood)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--image-type lxd&lt;/code&gt;: we want an LXD image (we could have also said:
&lt;code&gt;docker&lt;/code&gt;, but since there is some systemd/init stuff in our frecklet, indirectly, that won&amp;rsquo;t work in this case)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--source-image images:debian/10&lt;/code&gt;: the source image to use (notice
the &amp;lsquo;images:&amp;lsquo;-prefix, this is needed in this case to use the correct
LXD image index&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--image-name&lt;/code&gt;: the name of our new image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--frecklet-path $(pwd)/example-lxd.frecklet&lt;/code&gt; (absolute!) path to the
&lt;em&gt;frecklet&lt;/em&gt; that contains our provisioning instructions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--frecklet-vars &#39;{&amp;quot;...&amp;quot;}&#39;&lt;/code&gt;: additional variables (as a JASON
string) which are needed by our provisioning &lt;em&gt;frecklet&lt;/em&gt;. The
alternative to using this is hard-coding everything in the
&lt;em&gt;frecklet&lt;/em&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, once this command finished, you should be able to see the new
  image via:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ lxc image list
+----------------+--------------+--------+-----------------------------------------------+--------+-----------+-------------------------------+
|     ALIAS      | FINGERPRINT  | PUBLIC |                  DESCRIPTION                  |  ARCH  |   SIZE    |          UPLOAD DATE          |
+----------------+--------------+--------+-----------------------------------------------+--------+-----------+-------------------------------+
| freckles-image | f9600c979eba | no     | built with freckles.                          | x86_64 | 194.72MB  | Aug 10, 2019 at 10:37am (UTC) |
...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And we can use it like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute lxd-container-running --image-name &#39;freckles-image&#39; \
      --name &#39;freckles-example&#39; --register-addresses freckles_container_ip

╭╼ starting run
│  ├╼ running frecklet: lxd-container-running (on: localhost)
│  │  ├╼ starting Ansible run
│  │  │  ├╼ create/launch container &#39;freckles-example&#39;
│  │  │  │  ╰╼ ok
│  │  │  ╰╼ ok
│  │  ╰╼ ok
│  ╰╼ ok
╰╼ ok

Result:

    freckles_container_ip:
      eth0:
      - 10.10.10.100
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now point your browser to the container ip (10.10.10.100 in my case),
and you should see a message like: &amp;lsquo;freckles says &amp;ldquo;Hello World&amp;rdquo;, from my first image!&amp;rsquo;.&lt;/p&gt;

&lt;h3 id=&#34;re-using-our-frecklet&#34;&gt;Re-using our &lt;em&gt;frecklet&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;The main reason I wrote &lt;em&gt;freckles&lt;/em&gt; was to have a generic, flexible and
re-usable way to describe desired states of computational
environments. We already used our &lt;em&gt;frecklet&lt;/em&gt; to provision a running
(empty) LXD container, and to create an LXD container image from
it. If our &lt;em&gt;frecklet&lt;/em&gt; didn&amp;rsquo;t contain init-system-specific instructions
(setting up and restarting a systemd service unit), we could also use
it to build a Docker image. This won&amp;rsquo;t work here, but lets use it
instead to setup a remote server (like an EC2 instance, or a Digital
Ocean droplet):&lt;/p&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(empty) Ubuntu/Debian remote machine with public IP&lt;/li&gt;
&lt;li&gt;root or sudo access to that machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We don&amp;rsquo;t need to make any changes to our &lt;em&gt;frecklet&lt;/em&gt;, all we need to do
is change the &lt;code&gt;--target&lt;/code&gt; in our command:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute -t root@159.69.201.220 example-lxd.frecklet --from &amp;quot;a remote machine&amp;quot;

╭╼ starting run
│  ├╼ running frecklet: /home/markus/projects/frkl-dev/frkl.io/example-lxd.frecklet (on: 159.69.201.220)
│  │  ├╼ starting Ansible run
│  │  │  ├╼ updating apt cache
│  │  │  │  ╰╼ ok
│  │  │  ├╼ ensure rsync, ca-certificates and unzip packages are installed
│  │  │  │  ╰╼ ok
│  │  │  ├╼ creating freckles share folder
│  │  │  │  ╰╼ ok
│  │  │  ├╼ creating box basics marker file
│  │  │  │  ╰╼ ok
│  │  │  ├╼ recording python interpreter metadata
│  │  │  │  ╰╼ ok
│  │  │  ├╼ recording box metadata for later runs
│  │  │  │  ╰╼ ok
│  │  │  ├╼ Ensure nginx is installed.
│  │  │  │  ╰╼ ok
│  │  │  ├╼ Copy nginx configuration in place.
│  │  │  ├╼ reload nginx
│  │  │  │  ╰╼ ok
│  │  │  ├╼ write content to file: /etc/nginx/sites-enabled/localhost.http.conf
│  │  │  │  ╰╼ ok
│  │  │  ├╼ ensure user &#39;www-data&#39; exists
│  │  │  │  ╰╼ ok
│  │  │  ├╼ write content to file: /var/www/html/index.html
│  │  │  │  ╰╼ ok
│  │  │  ├╼ geerlingguy.nginx : reload nginx
│  │  │  │  ╰╼ ok
│  │  │  ╰╼ ok
│  │  ╰╼ ok
│  ╰╼ ok
╰╼ ok

$ curl http://159.69.201.220
&amp;lt;h1&amp;gt;&amp;lt;i&amp;gt;freckles&amp;lt;/i&amp;gt; says &amp;quot;Hello World&amp;quot;, from a remote machine!&amp;lt;/h1&amp;gt;%
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>On licensing freckles</title>
      <link>https://frkl.io/blog/on-licensing-freckles/</link>
      <pubDate>Mon, 17 Jun 2019 18:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/on-licensing-freckles/</guid>
      <description>

&lt;p&gt;Ok, I guess I have to write this. Why is &lt;em&gt;freckles&lt;/em&gt; licensed using &lt;a href=&#34;https://licensezero.com/licenses/parity&#34;&gt;the Parity Public license&lt;/a&gt;, a license that most people haven&amp;rsquo;t heard of (yet), that is not approved by FSF/OSI, and that is also very &lt;em&gt;very&lt;/em&gt; copy-left, compared to the usual suspects?&lt;/p&gt;

&lt;p&gt;There are a few reasons, and it took me quite a while to arrive at the conclusions I eventually arrived at. I&amp;rsquo;m pretty confident anything I say here has been said before, and most likely much more eloquent and exhaustive. Probably by &lt;a href=&#34;https://kemitchell.com/&#34;&gt;Kyle Mitchell&lt;/a&gt;, whose writings &lt;a href=&#34;https://writing.kemitchell.com/&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;https://blog.licensezero.com/&#34;&gt;here&lt;/a&gt; I can&amp;rsquo;t recommend enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sidenote&lt;/strong&gt;: Parity allows you to run software licensed with it in combination with other open-source software, as much as you want. If you want to use it in combination with non-open software, you&amp;rsquo;ll have to purchase an alternative license for the code in question. Read the license text, it&amp;rsquo;s very short!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Oh, one thing, before I start&lt;/em&gt;: I usually avoid calling &lt;em&gt;freckles&lt;/em&gt; &amp;lsquo;open-source&amp;rsquo;. Not because I think it is not &amp;lsquo;open-source software&amp;rsquo;, but because the OSI claims to own the term, and any license that is not approved by it should not be called &amp;lsquo;open-source&amp;rsquo;. A few (loud-ish) people on the usual opinion-haunts agree. So, that&amp;rsquo;s why I just don&amp;rsquo;t call &lt;em&gt;freckles&lt;/em&gt; open source software: because I&amp;rsquo;m not interested in that particular argument. In this blog post I will do so though. Because in this context here it&amp;rsquo;s just easier, and to me, software licensed using the Parity Public license counts as open-source software, and is not too far away from what Richard Stallman wanted, back when. In a lot of ways it&amp;rsquo;s probably closer than to what the OSI stands for today. But, as I said: not having that argument. This is really about my (personal) decision to use a very strong copy-left license.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Oh, and another thing&lt;/em&gt;: the main reason I wrote &lt;em&gt;freckles&lt;/em&gt; was because I very strongly felt that something like it should exists, and I could not understand that it didn&amp;rsquo;t yet. Because it seems really obvious to me, to a point where I can&amp;rsquo;t even explain why. I&amp;rsquo;ve actually waited a few years before I (reluctantly) started writing it. It&amp;rsquo;s not the most interesting thing to write, really. Anyway: the parts of me that have nothing to do with my programming-related obsessions obviously realize that the fact that nobody ever bothered writing it, in addition to the blank looks I usually get when I tell people about it, indicate that this is probably really nothing nobody ever wants to use. Which makes it a bit embarrassing when I talk about actually charging people money for it. For the purpose of this article, just assume I&amp;rsquo;m talking about something people would be at least somewhat inclined to pay for, ok?&lt;/p&gt;

&lt;p&gt;With all that being said:&lt;/p&gt;

&lt;h1 id=&#34;reasons&#34;&gt;Reasons!!!&lt;/h1&gt;

&lt;h2 id=&#34;idealism&#34;&gt;Idealism&lt;/h2&gt;

&lt;p&gt;I would like to live in a world where all software is open-source. Boring people will say that is not realistic, but boring people would say that, wouldn&amp;rsquo;t they? I reluctantly agree that this will not transpire in the next short to very long future, but hey, that doesn&amp;rsquo;t mean that we who think that this should be the case shouldn&amp;rsquo;t do their small parts. &lt;em&gt;Parity&lt;/em&gt; gives open source software a leg up, because it can be used without any problems from other open-source software, but needs to be purchased when people want to use it with code they don&amp;rsquo;t want to share.&lt;/p&gt;

&lt;h2 id=&#34;money&#34;&gt;Money&lt;/h2&gt;

&lt;p&gt;This probably sounds like a humble-brag, but I&amp;rsquo;m not really good at half-assing things. I don&amp;rsquo;t see that as a strength all of the time, but sometimes it is. Anyway, I wasn&amp;rsquo;t really happy with my first &amp;lsquo;proof-of-concept&amp;rsquo; for &lt;em&gt;freckles&lt;/em&gt;, even if it kind of worked. I really wanted to properly understand the thing I was trying to fix, and make it as &lt;em&gt;simple&lt;/em&gt; (not &lt;a href=&#34;https://www.infoq.com/presentations/Simple-Made-Easy/&#34;&gt;&lt;em&gt;easy&lt;/em&gt;&lt;/a&gt;) as I could. This took me about 3 or 4 re-writes. Now I&amp;rsquo;m happy (enough) in this regard. But I also spent a shi&lt;em&gt;p&lt;/em&gt;-load of time on it. And I wouldn&amp;rsquo;t have done it if I didn&amp;rsquo;t think there was at least a &lt;em&gt;very&lt;/em&gt; small chance that it could pay off in some other way than me being satisfied about having understood something. Motivations, and how the prospect of reward driving society, and all that.&lt;/p&gt;

&lt;p&gt;If I had chosen any of the &amp;lsquo;normal&amp;rsquo; open source licenses (even AGPL), there wouldn&amp;rsquo;t be much of an incentive for people to pay for &lt;em&gt;freckles&lt;/em&gt;. The triggers that enforce sharing your code just don&amp;rsquo;t apply. I could have, of course, chose one of the other open-source business models, not dual-licensing:&lt;/p&gt;

&lt;h3 id=&#34;open-source-business-models-and-what-i-don-t-like-about-them&#34;&gt;Open-source business models, and what I don&amp;rsquo;t like about them&lt;/h3&gt;

&lt;h4 id=&#34;donations&#34;&gt;&lt;strong&gt;Donations&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;This is not the relationship I want to have with my users. I don&amp;rsquo;t think any party in such a relationship should feel &amp;lsquo;thankful&amp;rsquo; for something the other party did. I don&amp;rsquo;t want to feel thankful for users having donated, even though they didn&amp;rsquo;t need to, and users shouldn&amp;rsquo;t need to feel thankful because I created something and gave it out for free. I like the sort of relationships that result from market-driven interactions much better: I take a risk, and spend time and money creating something I think can be of value for you. You wait until it is clear that thing is of value for you, and you pay for that value (plus a bit extra for the risk I took). My free decision to take that risk, your free decision to pay for a product after you compared it to other options. Nobody has to be thankful, and we can all be adults about it. No (perceived, or real) power imbalance.&lt;/p&gt;

&lt;h4 id=&#34;open-core&#34;&gt;&lt;strong&gt;Open core&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;I don&amp;rsquo;t like the overhead this creates, in terms of having to split up code more or less arbitrarily. Driven by business decisions, not what would make sense technically. A code-base likt that is much more cumbersome to deal with, especially in regards to having to setup everything twice (CI pipelines, release channels, &amp;hellip;). But more importantly, it&amp;rsquo;s going to be really difficult to align my incentives with my users interests.&lt;/p&gt;

&lt;p&gt;Also, &amp;lsquo;idealism&amp;rsquo;: everybody can use everything, if you make you own software freely available, you might have to have a slight advantage over your proprietary competitor by not having to pay.&lt;/p&gt;

&lt;h4 id=&#34;software-platform-whatever-as-a-service&#34;&gt;&lt;strong&gt;Software/platform/whatever as a service&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;This would have been possible for &lt;em&gt;freckles&lt;/em&gt;, and probably would have been a bit easier to implement too (but harder to run/maintain in the long run). But it would have taken away a lot of value from the user. The way it is now, &lt;em&gt;freckles&lt;/em&gt; is super-flexible, and can be used in a lot of circumstances, without much hassle at all: embed the binary in your project, use the Python library and Python code, write a small REST-wrapper around it and call it remotely, host the binary yourself, use my hosted version, etc. If it was a hosted service, users would have to trust me with their secrets, and data in general. I might still decide to provide such a hosted service at some point, but it&amp;rsquo;d be in addition to all the other options users can pick from.&lt;/p&gt;

&lt;p&gt;Also, I really dislike how there are so many startups creating SaaSes for things that &lt;em&gt;should&lt;/em&gt; just be libraries, if you look at it from a technical perspective. I see how MRR is nice, but really, this is getting pretty silly.&lt;/p&gt;

&lt;h4 id=&#34;corporate-sponsorship&#34;&gt;&lt;strong&gt;Corporate sponsorship&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;I could live with that, I guess. Depending on the company, and terms. Still, I like the idea of a software-cornershop with a handful (enough to sustain) users better.&lt;/p&gt;

&lt;h2 id=&#34;tit-for-tat&#34;&gt;Tit for tat&lt;/h2&gt;

&lt;p&gt;I think it&amp;rsquo;s only fair: if you don&amp;rsquo;t want to give me your software, why should I let you use mine? There are not a lot of good moral arguments to be made for why the freedom of people who don&amp;rsquo;t want to protect their users freedom should be protected. There is an argument to be made by open-source developers who want to protect &lt;em&gt;their&lt;/em&gt; users freedom (even if those users don&amp;rsquo;t want to protect &lt;em&gt;their&lt;/em&gt; users freedom in turn). If that&amp;rsquo;s you, fine, I&amp;rsquo;ll grant you that. But I might want you to show me what and how much you created and invested, first.&lt;/p&gt;

&lt;p&gt;For now, that&amp;rsquo;s all I can think of. Will add to this over time.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Data-centric environment management</title>
      <link>https://frkl.io/blog/data-centric-environment-management/</link>
      <pubDate>Mon, 22 Jan 2018 18:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/data-centric-environment-management/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This was written for a previous version of &lt;a href=&#34;https://freckles.io&#34;&gt;freckles&lt;/a&gt;. The code/examples in here won&amp;rsquo;t work anymore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;: Imagine you get a piece of data, some folder or zip file from a friend. It doesn&amp;rsquo;t matter what it is. Some source code in Python or Java or Cobol. Their dissertation in LaTEX. A backup of a Wordpress instance. A blender project. Research data. Anything, really.&lt;/p&gt;

&lt;p&gt;Imagine there is an application you can just point to that folder, and run it, without having to tell that application what that data is. Imagine that run automatically sets up your laptop so that you can instantly work with or use that data. Without you having to do anything else. No installing of applications by hand, no having to hunt for the right versions of those applications, no configuration. No compiling.&lt;/p&gt;

&lt;p&gt;That is what this is about.&lt;/p&gt;

&lt;p&gt;I hate repetition. If you are working in I.T., chances are you hate repetitive work also. Luckily, a lot of I.T. work is devoted to cutting down on repetitive work. Because, after all, that&amp;rsquo;s what computers are good at: give them the same problem several times, and they&amp;rsquo;ll work on it the same way all those several times. Without complaining, mostly. Even if they have to do it repetitively a million-billion times and then a million-billion times again.&lt;/p&gt;

&lt;p&gt;Besides any potential personal aversion against repetitive work one might have there is another reason humans shouldn&amp;rsquo;t be doing repetitive work if a computer can do it: the chance of making a mistake grows the more often you do a repetitive thing. And you might end up with a different end-result some of the time. Computers either do it always wrong, or if we&amp;rsquo;re lucky, always right. Provided, of course, somebody wrote tests for all possible and impossible edge cases. Which, naturally, we all do, every time.&lt;/p&gt;

&lt;p&gt;So, long story short, there is one (non-obvious, but very generic) repetitive thing that, over the years, annoyed me more than other repetitive things: setting up an environment on a computer (virtual, physical, whatever) in order for this computer to deal with a set of files/data that is of a type the computer isn&amp;rsquo;t prepared to deal with yet.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if I have Python source files, I need to make sure I have (the right version of) Python installed, a virtualenv created, and dependencies installed via &lt;code&gt;pip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;if I have markdown files representing content for this here blog, I need to setup and configure a webserver (say, &lt;code&gt;nginx&lt;/code&gt;), maybe install PHP and probably also some (the right) PHP libraries, then I have to download &lt;a href=&#34;https://getgrav.org&#34;&gt;grav&lt;/a&gt; and put it into the right folder so &lt;code&gt;nginx&lt;/code&gt; can find it&lt;/li&gt;
&lt;li&gt;if I have backup data of a service that needs migration to a new machine (virtual or not) I have to re-setup and configure the service, and restore the backup data in some way or other&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It appears to me that, if I know what type of data I deal with, and if I have a set of (ideally best) practices for that type of data, a computer would be able to do that sort of setting up for me. Right? &amp;hellip; RIGHT???&lt;/p&gt;

&lt;p&gt;Not only that, if the computer would know what kind of platform/distribution/version of distribution it runs (which it always does since, hey, it&amp;rsquo;s the one running it&amp;hellip;), and if it had instructions that outline what to do differently an each of those platforms, it could always, automatically, prepare a host environment that is hospitable to the kind of data in question, and there would be no manual intervention necessary. AT bloody ALL.&lt;/p&gt;

&lt;p&gt;What would be necessary is somebody preparing those sort of recipes, best practices and platform-dependent instructions for all the potential types of data we come across. In a way that the computer can understand. But, the good thing is, we could do that in a collaborative and evolutionary fashion, starting off with a simple use-case and best practice, and build on top of that to support more options, features, and platforms in the future. We&amp;rsquo;d have one place to improve a recipe for a given use-case or type of data, and that recipe would go through the normal stages of software development until it can be considered stable and comprehensive enough.&lt;/p&gt;

&lt;p&gt;So, what&amp;rsquo;s left is the glue, an application that runs on the computer, is pointed at the data we are interested in, parses that data (and potentially existing augmenting metadata), chooses the right recipes for that type of data and platform it runs on, and executes those recipes in the way the data/metadata demands.&lt;/p&gt;

&lt;p&gt;There are two classes of existing applications that do parts of what I&amp;rsquo;m describing: configuration management engines like &lt;a href=&#34;https://ansible.com&#34;&gt;Ansible&lt;/a&gt;, &lt;a href=&#34;https://saltstack.com/&#34;&gt;SaltStack&lt;/a&gt;, &lt;a href=&#34;https://puppet.com&#34;&gt;Puppet&lt;/a&gt;, etc., and build systems like &lt;a href=&#34;https://www.gnu.org/software/make/&#34;&gt;make&lt;/a&gt;, &lt;a href=&#34;https://maven.apache.org/&#34;&gt;maven&lt;/a&gt;, &lt;a href=&#34;https://github.com/ruby/rake&#34;&gt;Rake&lt;/a&gt; and so on. But those are either focused on a bigger infrastructure and network environment, only understand a certain type of data (Java project, Ruby project, &amp;hellip;), or are very low-level and don&amp;rsquo;t have the building blocks to manipulate the state of a machine in an efficient way. There might be other tools, but if there are, I don&amp;rsquo;t know about them.&lt;/p&gt;

&lt;p&gt;Now, all of this led me to work on &lt;a href=&#34;https://docs.freckles.io/en/latest/freckelize_command.html&#34;&gt;freckelize&lt;/a&gt;. &lt;code&gt;freckelize&lt;/code&gt; is part of a project called &lt;a href=&#34;https://github.com/makkus/freckles&#34;&gt;freckles&lt;/a&gt; which is designed as a layer on top of &lt;a href=&#34;https://ansible.com&#34;&gt;Ansible&lt;/a&gt;, and is an experiment to find ways to re-use all those existing tasty Ansible &lt;a href=&#34;http://docs.ansible.com/list_of_all_modules.html&#34;&gt;modules&lt;/a&gt; and &lt;a href=&#34;https://galaxy.ansible.com/&#34;&gt;roles&lt;/a&gt; for things besides &amp;lsquo;traditional&amp;rsquo; configuration management.&lt;/p&gt;

&lt;p&gt;In this blog post I&amp;rsquo;m not going into too much detail about how &lt;code&gt;freckelize&lt;/code&gt; works, what features &amp;ndash; aside from the basic ones &amp;ndash; it has, what the security implications of using a tool like that are. And anything else that might distract from getting across the basic idea behind it. I&amp;rsquo;ll write about all that in a follow-up post.&lt;/p&gt;

&lt;p&gt;So, to illustrate that basic idea I&amp;rsquo;ll use the very simple example of hosting a static webpage, where the data we work with is a single html file. I also wrote a more in-depth blog post about this exact usage scenario, so if you are interested in those details, check it out &lt;a href=&#34;https://frkl.io/blog/example-static-website&#34;&gt;here&lt;/a&gt; later.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: the &amp;lsquo;static-website&amp;rsquo; recipe I&amp;rsquo;m using below is currently only tested on Debian Stretch. Help me improve it and add more supported platforms?&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;The example dataset &amp;ndash; a single html file, plus an optional metadata file named &lt;code&gt;.freckle&lt;/code&gt; &amp;ndash; can be found here: &lt;a href=&#34;https://github.com/freckles-io/example-static-website&#34;&gt;https://github.com/freckles-io/example-static-website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s put those two files in a folder called &lt;code&gt;example-static-website&lt;/code&gt;. The &lt;code&gt;index.html&lt;/code&gt; file looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Now, what is all this?&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;No idea at all, mate.&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And this is &lt;code&gt;.freckle&lt;/code&gt; file, which contains additional metadata:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yml&#34;&gt;- static-website:
    static_website_domain: 127.0.0.1   # ip address or domain name used by this server
    static_website_port: 80            # port the webserver listens to
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This latter &lt;code&gt;.freckle&lt;/code&gt; file is optional, but useful to adjust some of &lt;code&gt;freckelize&lt;/code&gt;&amp;rsquo;s behavior. It uses &lt;code&gt;yaml&lt;/code&gt; syntax, and, at it&amp;rsquo;s root level, contains a list of types of data to be considered, including potential variables per type. In this case it contains two variables, which both are set to default values, which means that this file doesn&amp;rsquo;t affect behavior just yet.&lt;/p&gt;

&lt;p&gt;So, this is what you have to do (assuming &lt;code&gt;freckles&lt;/code&gt; is already installed) to install a webserver (&lt;code&gt;nginx&lt;/code&gt; in this case) and configure it to host our website:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;freckelize static-website -f example-static-website
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Done. Simple, he? Check if it&amp;rsquo;s working by visiting: &lt;a href=&#34;http://127.0.0.1&#34;&gt;http://127.0.0.1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since this folder already contains a &lt;code&gt;.freckle&lt;/code&gt;  file that includes the &amp;lsquo;static-website&amp;rsquo; type, we could have just omitted the &amp;lsquo;static-website&amp;rsquo; command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;freckelize -f example-static-website
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the case that we don&amp;rsquo;t have that folder on our local machine but only on Github, we can let &lt;code&gt;freckelize&lt;/code&gt; also clone it for us, before doing it&amp;rsquo;s thing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;freckelize -f https://github.com/freckles-io/example-static-website.git -t /var/lib/freckles
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will check out the repository as a sub-folder of &lt;code&gt;/var/lib/freckles&lt;/code&gt; (which is a nice place to collect those sort of folders). Then it&amp;rsquo;ll do exactly what it did before, when using the local folder.&lt;/p&gt;

&lt;p&gt;There are more scenarios &lt;code&gt;freckelize&lt;/code&gt; supports, like for example pointing it to a remote tarball of the data. Refer to &lt;a href=&#34;https://docs.freckles.io&#34;&gt;the documentation&lt;/a&gt; for details. In the future, anyway. Need to re-write parts of that documentation to bring it up-to-date. Soooooorry.&lt;/p&gt;

&lt;p&gt;As an example this is not really impressive, I&amp;rsquo;m sure, as this is something that would not take a lot of time to do by hand. Just a &lt;code&gt;sudo apt-get install nginx&lt;/code&gt;, and some configuration editing somewhere in &lt;code&gt;/etc/nginx/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To illustrate how easy it is to accomplish more complex tasks: let&amp;rsquo;s say we want to host that website on a VPS somewhere, via https and a (valid) &lt;a href=&#34;https://letsencrypt.org/&#34;&gt;Let&amp;rsquo;s encrypt&lt;/a&gt; certificate. This is supported by the &lt;code&gt;static-website&lt;/code&gt; (&lt;a href=&#34;https://github.com/freckles-io/adapters/tree/master/web/static-website&#34;&gt;source&lt;/a&gt;) recipe (&amp;lsquo;adapter&amp;rsquo; in &lt;code&gt;freckelize&lt;/code&gt;-speak). We need to provide a bit more information to &lt;code&gt;freckelize&lt;/code&gt; though, as it wouldn&amp;rsquo;t know the domain name to use, and the email address the folks over at &amp;ldquo;Let&amp;rsquo;s encrypt&amp;rdquo; require. Also, we need to configure DNS so that the domain name we use points to the VPS IP address. This last thing has to be done manually though, and since it depends a lot on the providers that are used I won&amp;rsquo;t write about how to accomplish it.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s edit the &lt;code&gt;.freckle&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- freckle:
    owner: www-data
    group: www-data

- static-website:
    static_website_domain: example.frkl.io
    static_website_port: 80
    lets_encrypt_email: makkus@frkl.io
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We add a generic section (always called &amp;lsquo;&lt;code&gt;freckle&lt;/code&gt;&amp;rsquo;) about who should own the data (which will also determine the user &lt;code&gt;nginx&lt;/code&gt; runs under). We leave the port as &amp;lsquo;80&amp;rsquo;, the adapter will automatically create a vhost configuration to forward all traffic to the default https port (443) if configured to use https. The adapter is written in a way that, if it encounters the &lt;code&gt;lets_encrypt_email&lt;/code&gt; variable with a string other than &amp;lsquo;none&amp;rsquo;, it&amp;rsquo;ll use that value as email address and request a https certificate for the domain specified from the &amp;ldquo;Let&amp;rsquo;s encrypt&amp;rdquo; service. In addition, it&amp;rsquo;ll setup a cron job that makes sure that certificate will be re-newed before it expires.&lt;/p&gt;

&lt;p&gt;So, that was that. I hope all that made at least a tiny bit of sense to anybody other than myself&amp;hellip;&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a lot more to be said. For example, how that is different from &amp;lsquo;normal&amp;rsquo; configuration management, why you would choose one over the other, how one could compliment the other, how this could be used with technologies like LXC, Docker, Vagrant. What the disadvantages of using this kind of thing are. And what else could be done with it that I haven&amp;rsquo;t even hinted at yet.&lt;/p&gt;

&lt;p&gt;My plan is to write about all that and more in the future. So, please, do check back here every now and then.&lt;/p&gt;

&lt;p&gt;Also, get in touch if you have questions, or suggestions. Either via &lt;a href=&#34;mailto:makkus@posteo.de&#34;&gt;email&lt;/a&gt;, &lt;a href=&#34;https://gitter.im/freckles-io/Lobby&#34;&gt;gitter&lt;/a&gt;, or a &lt;a href=&#34;https://github.com/makkus/freckles/issues&#34;&gt;Github issue&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Writing declarative command-line scripts, using Ansible modules and roles</title>
      <link>https://frkl.io/blog/writing-declarative-commandline-scripts/</link>
      <pubDate>Sat, 04 Nov 2017 13:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/writing-declarative-commandline-scripts/</guid>
      <description>

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This was written for a previous version of &lt;a href=&#34;https://freckles.io&#34;&gt;freckles&lt;/a&gt;. The code/examples in here won&amp;rsquo;t work anymore.&lt;/p&gt;

&lt;p&gt;Ever wanted to just quickly run a few Ansible tasks or apply a role from &lt;em&gt;Ansible Galaxy&lt;/em&gt;, without having to manually setup &lt;em&gt;Ansible&lt;/em&gt;, or create an inventory, and/or download role(s) from &lt;em&gt;Ansible Galaxy&lt;/em&gt;, etc&amp;hellip;? Or have you ever wished you could write a re-usable command-line script using &lt;em&gt;Ansible modules&lt;/em&gt; and &lt;em&gt;roles&lt;/em&gt;? Or, maybe you haven&amp;rsquo;t thought about it before, but now that I mention it&amp;hellip;&lt;/p&gt;

&lt;p&gt;If, this here blog post is for you.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re going to be using the &lt;code&gt;frecklecute&lt;/code&gt; command-line interface for this, which is part of the &lt;a href=&#34;https://github.com/makkus/freckles&#34;&gt;&lt;em&gt;freckles&lt;/em&gt;&lt;/a&gt; package. To learn more about &lt;em&gt;freckles&lt;/em&gt; itself: I&amp;rsquo;ve written about what it is and what you can do with it &lt;a href=&#34;https://frkl.io/blog/so-i-made-this-thing&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;tldr-show-me-the-goods&#34;&gt;tldr; show me the goods&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s one such example script (a &amp;lsquo;frecklecutable&amp;rsquo;) which sets up a user account (if it doesn&amp;rsquo;t exist yet) and makes sure the user is part of the &lt;code&gt;wheel&lt;/code&gt; group (which will also be created if necessary). The script also sets up &amp;lsquo;passwordless&amp;rsquo; &lt;em&gt;sudo&lt;/em&gt; permissions for that &lt;code&gt;wheel&lt;/code&gt; group.&lt;/p&gt;

&lt;p&gt;Right. This is the script (let&amp;rsquo;s name it &lt;code&gt;setup_sudo_user&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;doc:
  short_help: &amp;quot;setup new sudo user&amp;quot;
  help: &amp;quot;Sets up a new user with (passwordless) sudo privileges.\n\nInstalls the &#39;sudo&#39; package if necessary, and creates a group &#39;wheel&#39; which will be allowed passwordless sudo-access.&amp;quot;

args:
  user_name:
     help: &amp;quot;the name of the user&amp;quot;
     is_var: false
     required: yes
  password:
     help: &amp;quot;the user password hash (generate with &#39;mkpasswd -m sha-512&#39;)&amp;quot;
     is_var: false
     required: yes

tasks:
  - group:
      name: wheel
      state: present
  - package:
      name: sudo
      state: present
  - lineinfile:
      dest: /etc/sudoers
      state: present
      regexp: &amp;quot;^%wheel&amp;quot;
      line: &amp;quot;%wheel ALL=(ALL) NOPASSWD: ALL&amp;quot;
      validate: &amp;quot;/usr/sbin/visudo -cf %s&amp;quot;
  - user:
      name: &amp;quot;{{:: user_name ::}}&amp;quot;
      password: &amp;quot;{{:: password ::}}&amp;quot;
      update_password: always
      groups: wheel
      append: yes

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, we use the &lt;a href=&#34;http://yaml.org/&#34;&gt;yaml&lt;/a&gt; format to describe what we want to achive. To use this script, assuming &lt;a href=&#34;https://docs.freckles.io/en/latest/readme.html#really-quick-start&#34;&gt;we already bootstrapped &lt;em&gt;freckles&lt;/em&gt;&lt;/a&gt;, all we need to do is (as the &amp;lsquo;root&amp;rsquo; user, in this case):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;# frecklecute setup_sudo_user --help
Usage: frecklecute setup_sudo_user [OPTIONS]

  Setups a new user with (passwordless) sudo privileges.

  Installs the &#39;sudo&#39; package if necessary, and creates a group &#39;wheel&#39;
  which will be allowed passwordless sudo-access.

Options:
  --password TEXT   the user password hash (generate with &#39;mkpasswd -m
                    sha-512&#39;)  [required]
  --user_name TEXT  the name of the user  [required]
  --help            Show this message and exit.

  For more information about frecklecute and the freckles project, please
  visit: https://github.com/makkus/freckles

# mkpasswd -m sha-512 hello_password
$6$h5OgOaSfa$rwIgBF1Ds/YKx9200agirpmdjG/8D5ThsM3AG9ozvlwci3DzZrBcqRA6LbOQMRAStQop0MWlDes5atB/E7BR6.

# frecklecute setup_sudo_user --user_name fancy_new_user --password &#39;$6$h5OgOaSfa$rwIgBF1Ds/YKx9200agirpmdjG/8D5ThsM3AG9ozvlwci3DzZrBcqRA6LbOQMRAStQop0MWlDes5atB/E7BR6&#39;

* starting tasks (on &#39;localhost&#39;)...
 * starting custom tasks:
     * group... ok (changed)
     * package... ok (no change)
     * lineinfile... ok (changed)
     * user... ok (changed)
   =&amp;gt; ok (changed)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That was easy, right?&lt;/p&gt;

&lt;h2 id=&#34;why-should-i-use-that-when-should-i-use-that&#34;&gt;Why should I use that? When should I use that&lt;/h2&gt;

&lt;p&gt;This is not something that couldn&amp;rsquo;t be done with a bash script, or just plain &lt;em&gt;Ansible&lt;/em&gt;. If you already have setup &lt;em&gt;Ansible&lt;/em&gt;, it probably makes sense to just use that. If not, then this is an easy way to create scripts to manage local machines, still taking advantage of the power of &lt;em&gt;Ansible&lt;/em&gt;, and the hundreds or thousands of existing &lt;em&gt;modules&lt;/em&gt; and &lt;em&gt;roles&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Compared to a bash script, I think this is quite well suited in cases where you want to manage state on a machine. Not so much (rather, not at all) when you have &amp;lsquo;actual&amp;rsquo; work to do, like for example parsing a huge chunk of text files.&lt;/p&gt;

&lt;p&gt;A declarative script like the example above is much easier to read (I think, anyway), and in most cases the script you are writing will be &lt;a href=&#34;https://en.wikipedia.org/wiki/Idempotence&#34;&gt;idempotent&lt;/a&gt;, which you might or might not appreciate. It is certainly handy not having to check states or files or installed applications and handle those cases differently depending on the result of the check, because this is already done in every one of your building blocks. I&amp;rsquo;m not saying it&amp;rsquo;s not possible to write idempotent bash scripts, but I&amp;rsquo;d argue it&amp;rsquo;s quite a bit more work than just re-using all those readymade &lt;em&gt;Ansible modules&lt;/em&gt; and &lt;em&gt;roles&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Plus, you know. All those readymade &lt;em&gt;Ansible modules&lt;/em&gt; and &lt;em&gt;roles&lt;/em&gt;. There is one for almost everything you can imagine&amp;hellip;&lt;/p&gt;

&lt;h2 id=&#34;i-see-i-see-how-does-that-work-then&#34;&gt;I see, I see. How does that work then?&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s go through this script, and see how that works. A &lt;em&gt;frecklecutable&lt;/em&gt; supports 5 key-names in the root of the document: &lt;code&gt;doc&lt;/code&gt;, &lt;code&gt;defaults&lt;/code&gt;, &lt;code&gt;args&lt;/code&gt;, &lt;code&gt;vars&lt;/code&gt; and &lt;code&gt;tasks&lt;/code&gt;. Only the last one, &lt;code&gt;tasks&lt;/code&gt; is required for a valid &lt;em&gt;frecklecutable&lt;/em&gt;. To learn more about the keys not covered here, visit the &lt;a href=&#34;https://docs.freckles.io/en/latest/writing_frecklecutables.html&#34;&gt;&lt;em&gt;frecklecutable&lt;/em&gt; documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;doc&#34;&gt;&lt;code&gt;doc&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;The values under the &lt;code&gt;doc&lt;/code&gt; key help make a nice commandline application out of the &lt;em&gt;frecklecutable&lt;/em&gt;. As you can see in the example above, &lt;code&gt;frecklecute setup_sudo_user --help&lt;/code&gt; prints out a nice help message with the text we assign to the &lt;code&gt;help&lt;/code&gt; key, along usage hints for any potential arguments to the script.&lt;/p&gt;

&lt;h3 id=&#34;args&#34;&gt;&lt;code&gt;args&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This &lt;code&gt;key&lt;/code&gt; gathers all user specify-able command-line arguments of the &lt;em&gt;frecklecutable&lt;/em&gt;. Under the hood this uses the &lt;a href=&#34;http://click.pocoo.org/6/&#34;&gt;Click python package&lt;/a&gt;, so you can use most of the &amp;lsquo;click&amp;rsquo;-supported options for such an option or argument. More details can be found in the &lt;em&gt;freckles&lt;/em&gt; documentation, but here&amp;rsquo;s a quick example of the kind of customization that&amp;rsquo;s possible:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;become_root:
  help: whether to become root for this task or not
  arg_name: become
  required: false
  is_flag: true
  default: false
  is_var: false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates a variable with the name &amp;lsquo;become_root&amp;rsquo;, which is of type &lt;code&gt;boolean&lt;/code&gt; (because it&amp;rsquo;s specified as a flag), which is not required and defaults to &amp;lsquo;false&amp;rsquo; if not specified by the user (by providing the &lt;code&gt;--become&lt;/code&gt; option). It also contains a short help text to tell the user what it means to set it.&lt;/p&gt;

&lt;p&gt;The only &amp;lsquo;non-Click&amp;rsquo; key in this example is the &lt;code&gt;is_var&lt;/code&gt; one. This tells &lt;em&gt;frecklecute&lt;/em&gt; to not add the resulting value to every task in the &lt;code&gt;tasks&lt;/code&gt; list, but use it for templating purposes. More details on this can be found &lt;a href=&#34;https://docs.freckles.io/en/latest/frecklecutables_templating.html&#34;&gt;here&lt;/a&gt;. In our example, both &lt;code&gt;user_name&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; are used as templating variables.&lt;/p&gt;

&lt;h3 id=&#34;tasks&#34;&gt;&lt;code&gt;tasks&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This is the main section of a &lt;em&gt;frecklecutable&lt;/em&gt;, and where things get done. This key contains a list of tasks to execute. Those tasks can be either &lt;em&gt;Ansible&lt;/em&gt; &lt;a href=&#34;https://docs.ansible.com/modules.html&#34;&gt;modules&lt;/a&gt;, or &lt;a href=&#34;https://docs.ansible.com/ansible/2.4/playbooks_reuse_roles.html&#34;&gt;roles&lt;/a&gt;. In contrast to &lt;em&gt;Ansible playbooks&lt;/em&gt;, &lt;em&gt;modules&lt;/em&gt; and &lt;em&gt;roles&lt;/em&gt; are treated the same within a &lt;em&gt;frecklecutable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are two ways to define a task item in the task list, a verbose, &amp;lsquo;exploded&amp;rsquo; way which has yet to be documented and written about, and a concise, short way which I&amp;rsquo;ll describe here. The &amp;lsquo;exploded&amp;rsquo; way is basically a dictionary with explicit metadata, and it can be necessary when using one of the more uncommon features or special cases. Both can be used interchangeably, as internally a short description is converted into the more explicit, verbose way.&lt;/p&gt;

&lt;p&gt;Anyway, to add a task to the list, the most important thing is it&amp;rsquo;s name. A name can either be an alias you define (which we&amp;rsquo;ll ignore for the purpose of this blog post, but can be read about &lt;a href=&#34;https://docs.freckles.io/en/latest/writing_frecklecutables.html#task-alias&#34;&gt;here&lt;/a&gt;), the name of &lt;a href=&#34;http://docs.ansible.com/ansible/latest/list_of_all_modules.html&#34;&gt;a module&lt;/a&gt;, or the name of a &lt;a href=&#34;https://galaxy.ansible.com/&#34;&gt;role from Ansible Galaxy&lt;/a&gt;. &lt;code&gt;frecklecute&lt;/code&gt; will know which is which, because &lt;em&gt;roles&lt;/em&gt; always contain a &amp;lsquo; . &amp;rsquo; in their name, whereas modules never do.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s have a look at the example from above:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;tasks:
  - group:
      name: wheel
      state: present
  - package:
      name: sudo
      state: present
  - lineinfile:
      dest: /etc/sudoers
      state: present
      regexp: &amp;quot;^%wheel&amp;quot;
      line: &amp;quot;%wheel ALL=(ALL) NOPASSWD: ALL&amp;quot;
      validate: &amp;quot;/usr/sbin/visudo -cf %s&amp;quot;
  - user:
      name: &amp;quot;{{:: user_name ::}}&amp;quot;
      password: &amp;quot;{{:: password ::}}&amp;quot;
      update_password: always
      groups: wheel
      append: yes
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Those are all &lt;em&gt;Ansible modules&lt;/em&gt;. The tasks are all specified as &amp;lsquo;single-key&amp;rsquo; dictionaries, with the single key being the name of the &lt;em&gt;module&lt;/em&gt; (or &lt;em&gt;role&lt;/em&gt;), and the value of the key being a dictionary using any of the supported keys of a &lt;em&gt;module&lt;/em&gt;: &lt;a href=&#34;http://docs.ansible.com/group_module.html&#34;&gt;group&lt;/a&gt;, &lt;a href=&#34;http://docs.ansible.com/package_module.html&#34;&gt;package&lt;/a&gt;, &lt;a href=&#34;http://docs.ansible.com/lineinfile_module.html&#34;&gt;lineinfile&lt;/a&gt;, and &lt;a href=&#34;http://docs.ansible.com/user_module.html&#34;&gt;user&lt;/a&gt;. This is a slightly unusual way to use the &lt;code&gt;yaml&lt;/code&gt;-syntax, but I found it to be the easiest to read (and write, for that matter) &amp;ndash; something that was fairly important to me.&lt;/p&gt;

&lt;p&gt;As &lt;code&gt;frecklecute&lt;/code&gt; supports basic templating (using &lt;a href=&#34;http://jinja.pocoo.org/docs/latest/&#34;&gt;Jinja2&lt;/a&gt;, similar to &lt;em&gt;Ansible&lt;/em&gt; itself), any values under &lt;code&gt;tasks&lt;/code&gt; can contain templating markers (&lt;code&gt;{{::&lt;/code&gt; and &lt;code&gt;::}}&lt;/code&gt;, we don&amp;rsquo;t use the &amp;lsquo;normal&amp;rsquo; Jinja2 markers, because we want to be able to &amp;lsquo;forward&amp;rsquo; those to &lt;em&gt;Ansible&lt;/em&gt; and use vars like &lt;code&gt;{{ ansible_env.USER }}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;So, how would we use &lt;em&gt;Ansible roles&lt;/em&gt; with this then? In case you&amp;rsquo;ve never heard of &lt;em&gt;Ansible roles&lt;/em&gt;: those are basically collections of &lt;em&gt;tasks&lt;/em&gt;, which may or may not support different platforms to do one particular thing. For example, setting up the &lt;em&gt;nginx&lt;/em&gt; webserver, or &lt;em&gt;ldap&lt;/em&gt; authentication. Similar to what we do in our example here, there are also roles that can do some basic security- and user-management.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s have a look at the &lt;code&gt;geerlingguy.security&lt;/code&gt; role from &lt;a href=&#34;https://github.com/geerlingguy/ansible-role-security&#34;&gt;here&lt;/a&gt;. This can do the &amp;lsquo;sudo&amp;rsquo; setup, as well as some other basic stuff that is considered &amp;lsquo;good practice&amp;rsquo;, like setting up &lt;em&gt;fail2ban&lt;/em&gt; and unattended security updates. The following is how you&amp;rsquo;d use it to setup a passwordless sudo user with it. You&amp;rsquo;d create a playbook that contains:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- hosts: localhost
  vars_files:
    - vars/main.yml
  roles:
    - geerlingguy.security
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And put this in any of the places where you add variables:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;security_sudoers_passwordless:
  - johndoe
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This role supports other basic security tasks, like for example controlling ssh server behaviour, like allowing or disallowing password authentication. Do do that, as well as prevent root ssh logins, you could add:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;security_ssh_password_authentication: &amp;quot;no&amp;quot;
security_ssh_permit_root_login: &amp;quot;no&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Translating this into a (minimal) *frecklecutable would look like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;args:
  user_name:
     help: the name of the user
     is_var: false
     required: yes
  password:
     help: the user password hash (generate with &#39;mkpasswd -m sha-512&#39;)
     is_var: false
     required: yes
tasks:
  - user:
      name: &amp;quot;{{:: user_name ::}}&amp;quot;
      password: &amp;quot;{{:: password ::}}&amp;quot;
      update_password: always
  - geerlingguy.security:
      security_sudoers_passwordless:
        - &amp;quot;{{:: user_name ::}}&amp;quot;
      security_ssh_password_authentication: &amp;quot;no&amp;quot;
      security_ssh_permit_root_login: &amp;quot;no&amp;quot;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We still need to setup the user manually, as the role only adds the username to the &lt;code&gt;/etc/sudoers&lt;/code&gt; file. This &lt;em&gt;frecklecutable&lt;/em&gt; will create the user, download the &lt;code&gt;geerlingguy.security&lt;/code&gt; role from &lt;em&gt;Ansible Galaxy&lt;/em&gt;, then execute the role using the variables we provided:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute /frecklets/frecklecutables/setup_sudo_user_role --user_name fancy_new_user --password test

Downloading external roles...
  - downloading role &#39;security&#39;, owned by geerlingguy
  - downloading role from https://github.com/geerlingguy/ansible-role-security/archive/1.5.0.tar.gz
  - extracting geerlingguy.security to /home/vagrant/.cache/ansible-roles/geerlingguy.security
  - geerlingguy.security (1.5.0) was installed successfully

* starting tasks (on &#39;localhost&#39;)...
 * starting custom tasks:
     * USER... ok (changed)
   =&amp;gt; ok (changed)
 * applying role geerlingguy.security&#39;......
   - Include OS-specific variables. =&amp;gt; ok (no change)
   - Install fail2ban. =&amp;gt; ok (changed)
   - Ensure fail2ban is running and enabled on boot. =&amp;gt; ok (no change)
   - Update SSH configuration to be more secure. =&amp;gt;
       - {u&#39;regexp&#39;: u&#39;^PasswordAuthentication&#39;, u&#39;line&#39;: u&#39;PasswordAuthentication no&#39;} =&amp;gt; ok (no change)
       - {u&#39;regexp&#39;: u&#39;^PermitRootLogin&#39;, u&#39;line&#39;: u&#39;PermitRootLogin no&#39;} =&amp;gt; ok (changed)
       - {u&#39;regexp&#39;: u&#39;^Port&#39;, u&#39;line&#39;: u&#39;Port 22&#39;} =&amp;gt; ok (changed)
       - {u&#39;regexp&#39;: u&#39;^UseDNS&#39;, u&#39;line&#39;: u&#39;UseDNS no&#39;} =&amp;gt; ok (no change)
       - {u&#39;regexp&#39;: u&#39;^PermitEmptyPasswords&#39;, u&#39;line&#39;: u&#39;PermitEmptyPasswords no&#39;} =&amp;gt; ok (changed)
       - {u&#39;regexp&#39;: u&#39;^ChallengeResponseAuthentication&#39;, u&#39;line&#39;: u&#39;ChallengeResponseAuthentication no&#39;} =&amp;gt; ok (no change)
       - {u&#39;regexp&#39;: u&#39;^GSSAPIAuthentication&#39;, u&#39;line&#39;: u&#39;GSSAPIAuthentication no&#39;} =&amp;gt; ok (changed)
       - {u&#39;regexp&#39;: u&#39;^X11Forwarding&#39;, u&#39;line&#39;: u&#39;X11Forwarding no&#39;} =&amp;gt; ok (changed)
   - Add configured user accounts to passwordless sudoers. =&amp;gt;
       - fancy_new_user =&amp;gt; ok (changed)
   - Install unattended upgrades package. =&amp;gt; ok (changed)
   - Copy unattended-upgrades configuration files in place. =&amp;gt;
       - 10periodic =&amp;gt; ok (changed)
       - 50unattended-upgrades =&amp;gt; ok (changed)
   =&amp;gt; ok (changed)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Being able to do all this, combined with the multitude of available roles on &lt;em&gt;Ansible Galaxy&lt;/em&gt; can be quite powerful, and potentially save quite a bit of time in the day of a typical developer or systems/devops person.&lt;/p&gt;

&lt;h3 id=&#34;conventions&#34;&gt;Conventions&lt;/h3&gt;

&lt;p&gt;One of the main goals for &lt;code&gt;frecklecute&lt;/code&gt; was to have an easy-to-read scripting language, using &lt;em&gt;Ansible modules&lt;/em&gt; and &lt;em&gt;roles&lt;/em&gt; as building blocks. To achieve that, there are some conventions that need to be understood, at least once your scripts get more complex and use the more advanced features.&lt;/p&gt;

&lt;p&gt;Those conventions obviously need to be documented. Unfortunately this is still work-in-progress, and not finished yet. The most important of those relates to executing tasks with &amp;lsquo;root&amp;rsquo; or &amp;lsquo;sudo&amp;rsquo; permissions, which is something I&amp;rsquo;ve skipped over so far because we just used the &amp;lsquo;root&amp;rsquo; user to execute the examples.&lt;/p&gt;

&lt;p&gt;In &amp;lsquo;real life&amp;rsquo; we wouldn&amp;rsquo;t do that, but use a &amp;lsquo;normal&amp;rsquo; user account which has &amp;lsquo;sudo&amp;rsquo; permissions already. Without those we wouldn&amp;rsquo;t be able to install packages using the system manager, or add new users and groups.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ansible&lt;/em&gt; deals with this by providing a &lt;code&gt;become&lt;/code&gt; keyword, which, if set to &lt;code&gt;true&lt;/code&gt; means that &lt;em&gt;Ansible&lt;/em&gt; will execute the task (or role) in question using &amp;lsquo;root&amp;rsquo; permissions. This goes along with the &lt;code&gt;--ask-become-pass&lt;/code&gt; command-line flag in the &lt;code&gt;ansible-playbook&lt;/code&gt; application.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;frecklecute&lt;/code&gt; does support that flag as well, and you can also tell it to execute some tasks using elevated permissions. If that is necessary, one can either use the &amp;lsquo;exploded&amp;rsquo; form of task description I was referring to earlier, or, in the case of the short-form you specify the task name all uppercase. In our example, this would look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;tasks:
  - USER:
      name: &amp;quot;{{:: user_name ::}}&amp;quot;
      password: &amp;quot;{{:: password ::}}&amp;quot;
      update_password: always
  - GEERLINGGUY.SECURITY:
      security_sudoers_passwordless:
        - &amp;quot;{{:: user_name ::}}&amp;quot;
      security_ssh_password_authentication: &amp;quot;no&amp;quot;
      security_ssh_permit_root_login: &amp;quot;no&amp;quot;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously, this won&amp;rsquo;t work for roles that have uppercase characters in their name. In those cases we&amp;rsquo;d have to use the &amp;lsquo;exploded&amp;rsquo; form of configuration. Fortunately, this doesn&amp;rsquo;t happen very often.&lt;/p&gt;

&lt;h2 id=&#34;extras&#34;&gt;Extras&lt;/h2&gt;

&lt;p&gt;As a member of the &lt;em&gt;freckles&lt;/em&gt; family, there are a few extra features &lt;code&gt;frecklecute&lt;/code&gt; has that mesh quite nicely with being able to quickly write those state-altering scripts:&lt;/p&gt;

&lt;h3 id=&#34;transparent-bootstrap&#34;&gt;transparent bootstrap&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;freckles&lt;/em&gt; can use &lt;a href=&#34;https://github.com/makkus/inaugurate&#34;&gt;inaugurate&lt;/a&gt; for bootstrap, which means all you need to have installed to execute a &lt;em&gt;frecklecutable&lt;/em&gt; is either &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ curl https://freckles.io | bash -s -- frecklecute setup_sudo_user --user_name fancy_new_user --password &amp;lt;xxxxx&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;remote-script-locations&#34;&gt;remote script locations&lt;/h3&gt;

&lt;p&gt;You can keep a repository of your &lt;em&gt;frecklecutables&lt;/em&gt; somewhere online (e.g. your Github account), and let &lt;code&gt;frecklecute&lt;/code&gt; execute it from that remote place:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute gh:makkus/freckles/examples/setup_sudo_user --user_name fancy_new_user --password &amp;lt;xxxxxx&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;self-hosted-execution-context&#34;&gt;self-hosted execution context&lt;/h3&gt;

&lt;p&gt;This is related to the previous point &amp;ndash; and the details are a topic for another post &amp;ndash; but in addition to executing remote &lt;em&gt;frecklecutables&lt;/em&gt; you can also self-host all the roles you need for a &lt;code&gt;frecklecuteable&lt;/code&gt; run. That means that, except for the &lt;em&gt;freckles&lt;/em&gt; package itself (which you get from &lt;em&gt;pypi&lt;/em&gt;, all dependencies for a run can be hosted somewhere remotely by yourself, and as such re-used from any type of newly setup machine that has internet access). So, executing a &lt;em&gt;frecklecutable&lt;/em&gt; which is hosted somewhere on your Github account (alongside the &lt;em&gt;Ansible roles&lt;/em&gt; it uses) on a newly installed machine would look something like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ curl https://freckles.io | bash -s -- frecklecute -r gh:makkus/frecklets setup_sudo_user --user_name fancy_new_user --password &amp;lt;xxxxxxxxxxxx&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;using-a-frecklecutable-directly&#34;&gt;using a &lt;em&gt;frecklecutable&lt;/em&gt; directly&lt;/h3&gt;

&lt;p&gt;Since &lt;code&gt;frecklecute&lt;/code&gt; acts like a kind of interpreter for a &lt;em&gt;frecklecutable&lt;/em&gt;, you can use every &lt;em&gt;frecklecutable&lt;/em&gt; directly, like you do with &lt;em&gt;bash&lt;/em&gt; scripts for example. You need to add a shebang line to the beginning of the &lt;em&gt;yaml&lt;/em&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;#! /usr/bin/env frecklecute

tasks:
  ...
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then make it executable and put it into your path:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ chmod +x setup_sudo_user

$ mv setup_sudo_user /usr/local/bin    # assuming /usr/loca/bin is in your $PATH

$ setup_sudo_user --help

Usage: frecklecute /home/vagrant/.local/bin/setup_sudo_user
           [OPTIONS]

  Setups a new user with (passwordless) sudo privileges.

  Installs the &#39;sudo&#39; package if necessary, and creates a group &#39;wheel&#39;
  which will be allowed passwordless sudo-access.

Options:
  --password TEXT   the user password hash (generate with &#39;mkpasswd -m
                    sha-512&#39;)  [required]
  --user_name TEXT  the name of the user  [required]
  --help            Show this message and exit.

  For more information about frecklecute and the freckles project, please
  visit: https://github.com/makkus/freckles
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That is all. For now.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to manage *my* dotfiles with &#39;freckles&#39;</title>
      <link>https://frkl.io/blog/how-to-manage-my-dotfiles-with-freckles/</link>
      <pubDate>Tue, 24 Oct 2017 15:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/how-to-manage-my-dotfiles-with-freckles/</guid>
      <description>

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This was written for a previous version of &lt;a href=&#34;https://freckles.io&#34;&gt;freckles&lt;/a&gt;. The code/examples in here won&amp;rsquo;t work anymore.&lt;/p&gt;

&lt;p&gt;Welcome to the last part of this three-part series about managing dotfiles with &lt;em&gt;freckles&lt;/em&gt;, this is where it becomes interesting. The &lt;a href=&#34;https://frkl.io/blog/managing-dotfiles&#34;&gt;first part&lt;/a&gt; explained what dotfiles are, why one might want to manage them, and how to do that by hand. &lt;a href=&#34;https://frkl.io/blog/how-to-manage-your-dotfiles-with-freckles&#34;&gt;The second one&lt;/a&gt; explained how you can do the same thing using &lt;a href=&#34;https://github.com/makkus/freckles&#34;&gt;freckles&lt;/a&gt;, which is a configuration management tool &lt;a href=&#34;https://frkl.io/blog/so-i-made-this-thing&#34;&gt;I built on top of Ansible&lt;/a&gt;. This last installment will describe how I structured &lt;a href=&#34;https://github.com/makkus/dotfiles&#34;&gt;my own dotfiles&lt;/a&gt;, and how I use &lt;em&gt;freckles&lt;/em&gt; to get them onto new environments.&lt;/p&gt;

&lt;p&gt;[TOC]
Maybe I should start off with a few key-points I want to be able to do with my &lt;em&gt;dotfiles&lt;/em&gt;-setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I want to be able to easily setup a new machine that doesn&amp;rsquo;t have anything installed yet, with all my dotfiles and the applications I commonly use&lt;/li&gt;
&lt;li&gt;I want to be able to draw my dotfiles from multiple sources, not just one git repository&lt;/li&gt;
&lt;li&gt;I want to be able to choose which of my dotfiles are relevant for a certain environment (laptop, VM, container, remote server, etc.)&lt;/li&gt;
&lt;li&gt;I want my dotfiles to contain additional metadata describing other (relevant) details about the environment they live in (like additional packages to install, ensure certain folders exist, etc.)&lt;/li&gt;
&lt;li&gt;I want to be able to use alternative package managers, like for example &amp;lsquo;&lt;a href=&#34;https://nixos.org/nix/&#34;&gt;nix&lt;/a&gt;&amp;rsquo; to install some packages&lt;/li&gt;
&lt;li&gt;I want to be able to do all this on different platforms (at least Debian- and RedHat-based distros as well as Mac OS X, using mostly the same configuration, if possible)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;my-dotfiles&#34;&gt;My dotfiles&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s where I keep them: &lt;a href=&#34;https://github.com/makkus/dotfiles&#34;&gt;https://github.com/makkus/dotfiles&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a few things I do differently than what I&amp;rsquo;ve seen from most other people&amp;rsquo;s dotfiles:&lt;/p&gt;

&lt;h3 id=&#34;usage-profiles&#34;&gt;Usage &amp;lsquo;profiles&amp;rsquo;&lt;/h3&gt;

&lt;p&gt;I sort my dotfiles into different folders by &amp;lsquo;usage profile&amp;rsquo;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/makkus/dotfiles/tree/master/terminal&#34;&gt;&lt;strong&gt;terminal&lt;/strong&gt;&lt;/a&gt;: for terminal/console applications&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/makkus/dotfiles/tree/master/x&#34;&gt;&lt;strong&gt;x&lt;/strong&gt;&lt;/a&gt;: for X/gui applications&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/makkus/dotfiles/tree/master/sec&#34;&gt;&lt;strong&gt;sec&lt;/strong&gt;&lt;/a&gt;: misc applications where config files contain sorta semi-private information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within the &amp;lsquo;&lt;strong&gt;terminal&lt;/strong&gt;&amp;rsquo; and &amp;lsquo;&lt;strong&gt;x&lt;/strong&gt;&amp;rsquo; profiles, I have &amp;lsquo;sub-profiles&amp;rsquo;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;minimal&lt;/strong&gt;: applications used for a minimal environment, which I want to have available everywhere I do any sort of non-trivial work on (.bashrc, git config, &amp;lsquo;zile&amp;rsquo; - a small emacs-like editor I often use for small tasks)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;extra&lt;/strong&gt;: applications I use often-ish, but only I&amp;rsquo;m on my own machines (laptops, private server)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dev&lt;/strong&gt;: applications I use when I do development&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;i3-desktop&lt;/strong&gt;: (only in &amp;lsquo;&lt;strong&gt;x&lt;/strong&gt;&amp;rsquo;) my desktop environment setup, which I use on my 2 laptops, and sometimes in a VM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I like to be able to mix-and-match those. E.g. if I setup a new laptop or workstation, I&amp;rsquo;ll want all of those. If I login to a remote server I expect to work more than a minimal amount of time on, I want to use the &amp;lsquo;&lt;strong&gt;terminal&lt;/strong&gt;&amp;rsquo; profile, but only the &amp;lsquo;&lt;strong&gt;minimal&lt;/strong&gt;&amp;rsquo; and &amp;lsquo;&lt;strong&gt;extra&lt;/strong&gt;&amp;rsquo; (and, depending, maybe the &amp;lsquo;&lt;strong&gt;dev&lt;/strong&gt;&amp;rsquo;) sub-profiles. If I prepare a Docker container, I only want the &amp;lsquo;&lt;strong&gt;minimal&lt;/strong&gt;&amp;rsquo; sub-profile of &amp;lsquo;&lt;strong&gt;terminal&lt;/strong&gt;&amp;rsquo; (which I&amp;rsquo;ll delete once the container is finished to save space). On a new (graphical) VM I might only want the &amp;lsquo;&lt;strong&gt;minimal&lt;/strong&gt;&amp;rsquo; sub-profile of both &amp;lsquo;&lt;strong&gt;terminal&lt;/strong&gt;&amp;rsquo; and &amp;lsquo;&lt;strong&gt;x&lt;/strong&gt;&amp;rsquo;.&lt;/p&gt;

&lt;h3 id=&#34;applications&#34;&gt;Applications&lt;/h3&gt;

&lt;p&gt;I don&amp;rsquo;t want to have to install the applications my configurations refer to manually. If there is a configuration file for &lt;em&gt;git&lt;/em&gt;, I want &lt;em&gt;git&lt;/em&gt; to be available on that machine.&lt;/p&gt;

&lt;h3 id=&#34;additional-applications&#34;&gt;Additional applications&lt;/h3&gt;

&lt;p&gt;Even though it&amp;rsquo;s important to install the applications I have configurations for, most applications I use day-to-day either don&amp;rsquo;t need configuration, or I&amp;rsquo;m happy with the defaults so I never bother to configure anything in the first place.&lt;/p&gt;

&lt;p&gt;So, depending on the usage profile of an environment, I need additonal packages to be installed. &lt;code&gt;htop&lt;/code&gt; would be one example I use almost everywhere. Or &lt;code&gt;tree&lt;/code&gt;, which is often not installed by default.&lt;/p&gt;

&lt;h3 id=&#34;alternative-package-managers&#34;&gt;Alternative package managers&lt;/h3&gt;

&lt;p&gt;Setting up my workstation would be easy if all I&amp;rsquo;d install are system packages. Alas, for me, that&amp;rsquo;s not really a realistic scenario. Often I need more recent versions of a package than is available on Debian or Ubuntu, or it&amp;rsquo;s not available at all. One needs to add extra repositories, PPAs, whatnot. Some packages are not even packaged at all but need to be installed from scratch.&lt;/p&gt;

&lt;p&gt;Those are the additional sources I get my applications from:&lt;/p&gt;

&lt;h4 id=&#34;nix&#34;&gt;nix&lt;/h4&gt;

&lt;p&gt;For most of the user-facing applications I use, I prefer to use versions installed from the &lt;a href=&#34;https://github.com/NixOS/nixpkgs&#34;&gt;nix packages collection&lt;/a&gt;, using the &lt;a href=&#34;https://nixos.org/nix&#34;&gt;nix package manager&lt;/a&gt;. It&amp;rsquo;d go to far to explain why I prefer to do this, but the two main reasons are that I (mostly) get the latest (or at least reasonable fresh) versions of a package and don&amp;rsquo;t have to wait for my distribution of choice to catch up, and that I get the &lt;em&gt;exact&lt;/em&gt; same version and build of an application on different platforms. It&amp;rsquo;s also possible to install &lt;em&gt;nix&lt;/em&gt; on systems where you don&amp;rsquo;t have root access, but that&amp;rsquo;s a bit more involved, and I haven&amp;rsquo;t had to use that for a while now.&lt;/p&gt;

&lt;h4 id=&#34;conda&#34;&gt;conda&lt;/h4&gt;

&lt;p&gt;When working on Python projects, I prefer to use &lt;a href=&#34;https://conda.io&#34;&gt;conda&lt;/a&gt;. Again, the reasons for this choice are not really the topic of this blog post, so I&amp;rsquo;ll just say that I like how it&amp;rsquo;s possible to use most &amp;lsquo;system&amp;rsquo; packages that are (still) required as dependencies for certain Python packages (e.g. &lt;em&gt;cryptography&lt;/em&gt;, &lt;em&gt;pycrypt&lt;/em&gt;), without having to use the system package manager to install them. Everything is neatly contained in a &lt;em&gt;confa&lt;/em&gt; environment.&lt;/p&gt;

&lt;h4 id=&#34;git&#34;&gt;git&lt;/h4&gt;

&lt;p&gt;Some applications or plugins need to be installed via git. One example would be &lt;a href=&#34;https://spacemacs.org&#34;&gt;spacemacs&lt;/a&gt;, which is installed by checking out it&amp;rsquo;s source code into the &lt;code&gt;$HOME/.emacs.d&lt;/code&gt; directory. Or, &lt;a href=&#34;https://github.com/zplug/zplug&#34;&gt;zplug&lt;/a&gt;, a plugin manager for &lt;em&gt;zsh&lt;/em&gt; that also is installed by checking out it&amp;rsquo;s source into the home directory.&lt;/p&gt;

&lt;h4 id=&#34;pip&#34;&gt;pip&lt;/h4&gt;

&lt;p&gt;I also use a few (mostly command-line) applications directly from &lt;a href=&#34;https://pypi.python.org&#34;&gt;pypi&lt;/a&gt;, installed in a special (conda) virtualenv, symlinked into my &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&#34;stray-packages&#34;&gt;&amp;lsquo;stray&amp;rsquo; packages&lt;/h4&gt;

&lt;p&gt;Some applications I use (like for example &lt;a href=&#34;https://airvpn.org/enter/&#34;&gt;the AirVPN client &amp;lsquo;&lt;em&gt;eddie&lt;/em&gt;&amp;lsquo;&lt;/a&gt;, or &lt;a href=&#34;https://www.vagrantup.com/downloads.html&#34;&gt;Vagrant&lt;/a&gt;) only offer &lt;code&gt;deb&lt;/code&gt; or &lt;code&gt;rpm&lt;/code&gt; packages, but no repository or similar to install the package from. I don&amp;rsquo;t really like having to download and install those packages manually every time that becomes necessary.&lt;/p&gt;

&lt;h4 id=&#34;additional-repositories&#34;&gt;Additional repositories&lt;/h4&gt;

&lt;p&gt;A lot of applications nowadays come with their own package repository (e.g. PPA in Ubuntu) which contains the application and it&amp;rsquo;s dependencies as sytem-packages. In some cases this is the only way to get a package on a machine, without having to compile from source.&lt;/p&gt;

&lt;h4 id=&#34;others&#34;&gt;others&lt;/h4&gt;

&lt;p&gt;There are more sources I get packages from. For example, I use some &lt;em&gt;Vagrant&lt;/em&gt; plugins, so &lt;em&gt;Vagrant&lt;/em&gt; itself can be considered a plugin manager.&lt;/p&gt;

&lt;p&gt;Also, even though I don&amp;rsquo;t use it myself, but people get packages via &lt;a href=&#34;https://www.npmjs.com/&#34;&gt;npm&lt;/a&gt;, &lt;a href=&#34;https://rubygems.org/&#34;&gt;ruby gems&lt;/a&gt;, &lt;a href=&#34;https://www.haskell.org/cabal/&#34;&gt;cabal&lt;/a&gt;, etc. Ideally, I&amp;rsquo;d like to be able to easily install packages from any of those sources as well (including &amp;lsquo;transparent&amp;rsquo; installation of the package manager involved).&lt;/p&gt;

&lt;h3 id=&#34;application-less-config-files&#34;&gt;&amp;lsquo;application-less&amp;rsquo; config files&lt;/h3&gt;

&lt;p&gt;With &amp;lsquo;application-less&amp;rsquo; I mean config (or similar) files that need to be &amp;lsquo;stowed&amp;rsquo; (put into place), but don&amp;rsquo;t need any packages installed. One example would be &lt;a href=&#34;https://github.com/makkus/bits-and-pieces/tree/master/fonts&#34;&gt;additional fonts I use in my desktop environment&lt;/a&gt;, which need to sit in the &lt;code&gt;$HOME/.fonts&lt;/code&gt; folder. I have those in an extra git repository because I don&amp;rsquo;t want to have to checkout the added &amp;lsquo;bulk&amp;rsquo; of too many fonts everywhere I go and where they are not needed (e.g. terminal environments).&lt;/p&gt;

&lt;h3 id=&#34;encrypted-config-files&#34;&gt;Encrypted config files&lt;/h3&gt;

&lt;p&gt;I like to encrypt some of my semi-private config files before uploading them to github. One example would be email configuration, where I don&amp;rsquo;t want the world to see my account details. I&amp;rsquo;d never upload any configuration file containing a password, even encrypted, but some files I consider private enough so I prefer the world not to see them, but not important enough to worry too much if that would happen by accident.&lt;/p&gt;

&lt;p&gt;I found &lt;a href=&#34;https://github.com/AGWA/git-crypt&#34;&gt;git-crypt&lt;/a&gt; to be an adequate solution for this use-case. It uses my gpg key to encrypt certain files before upload to the git repository, and you can do a &lt;code&gt;git-crypt unlock&lt;/code&gt; on first checkout (provided your gpg-key is in place).&lt;/p&gt;

&lt;h3 id=&#34;additional-provisioning-tasks&#34;&gt;Additional provisioning tasks&lt;/h3&gt;

&lt;p&gt;Checking out dotfiles, sym-linking them into the home directory, and installing applications is fun, but usually there are always additional tasks to be done before one can use a newly provisioned machine. Those are often not too many, so they can be done by hand. But you&amp;rsquo;ll have to remember what exactly you did the last time you setup your machine, or you have to document it. I haven&amp;rsquo;t been too good at either of those tasks in the past. Anyway, for my environment, those tasks include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating certain folders some applications expect but don&amp;rsquo;t create themselves&lt;/li&gt;
&lt;li&gt;copy my i3 X xsession desktop file to &lt;code&gt;/usr/share/xsessions&lt;/code&gt; so the login manager picks it up&lt;/li&gt;
&lt;li&gt;copy the touchscreen configuration for my external monitor to &lt;code&gt;/etc/X11/xorg.conf.d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;import my public gpg key stub (I&amp;rsquo;m using a Yubikey to hold the actual key)&lt;/li&gt;
&lt;li&gt;set the trust of my gpg key to &amp;lsquo;ultimate&amp;rsquo;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ideally, I only want to execute the tasks that are relevant to the particular profile I selected for the environment I&amp;rsquo;m on. For example, most of the time I don&amp;rsquo;t need to import my gpg key when I setup a VM.&lt;/p&gt;

&lt;h2 id=&#34;automating-all-this&#34;&gt;Automating all this&lt;/h2&gt;

&lt;p&gt;If I only wanted to do all this every few months, to setup a new, or re-setup an old workstation, I wouldn&amp;rsquo;t mind doing it all manually. I really wanted to use my dotfiles in most of the environments I do serious work on, and at some stage I decided I wanted to be able to use a framework that&amp;rsquo;d be able to setup working environments in an automated and flexible fashion. Hence &lt;em&gt;freckles&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&#34;bootstrapping-with-inaugurate&#34;&gt;Bootstrapping (with &lt;code&gt;inaugurate&lt;/code&gt;)&lt;/h3&gt;

&lt;p&gt;One of the main drivers behind writing &lt;em&gt;freckles&lt;/em&gt; was me getting annoyed always having to setup requirements and dependencies before being able to run my bootstrap script which then would checkout my dotfiles, and install applications. I really wanted to do all this with only one command, and I wanted that command to work on all the machines and platforms I work on. Basically, what I needed was a bootstrap script for my bootstrap script. This is what &lt;a href=&#34;https://github.com/makkus/inaugurate&#34;&gt;&lt;code&gt;inaugurate&lt;/code&gt;&lt;/a&gt; is. I&amp;rsquo;ve written about this and how it works in probably every blog post and readme about &lt;em&gt;freckles&lt;/em&gt; I&amp;rsquo;ve written so far, but just for good measure, in case you haven&amp;rsquo;t read any of those (yet):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;inaugurate&lt;/em&gt; can install an application and it&amp;rsquo;s requirements as well as execute it in one go. The only requirement for the machine it is run on is either &lt;code&gt;wget&lt;/code&gt; or &lt;code&gt;curl&lt;/code&gt;. It can be executed with or without &lt;em&gt;sudo&lt;/em&gt; permissions, and depending which one it is it uses different ways to install the application (either using system packages, or &lt;em&gt;conda&lt;/em&gt;). This is done by directly executing the bash script &lt;code&gt;wget&lt;/code&gt; or &lt;code&gt;curl&lt;/code&gt; downloads. If that concerns you, read &lt;a href=&#34;https://docs.freckles.io/en/latest/trust.html&#34;&gt;this&lt;/a&gt;, &lt;a href=&#34;https://github.com/makkus/inaugurate#is-this-secure&#34;&gt;this&lt;/a&gt;, and &lt;a href=&#34;https://docs.freckles.io/en/latest/bootstrap.html&#34;&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first time you need an &amp;lsquo;inauguratable&amp;rsquo; application, you prepend the command you want to execute with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl https://freckles.io | bash -s -- [command incl. arguments]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After this, and after you either logged out and logged in again, or you sourced your &lt;code&gt;.profile&lt;/code&gt; (&lt;code&gt;source $HOME/.profile&lt;/code&gt;) to get &lt;em&gt;freckles&lt;/em&gt; into your &lt;code&gt;$PATH&lt;/code&gt;, you can use the inaugurated application directly. So, this is the one command I have to execute to get a new workstation setup with all my config files and applications, and extra bits and pieces:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre&gt;&lt;code&gt;curl https://freckles.io | bash -s -- freckelize dotfiles -f gh:makkus/dotfiles
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Check out the &lt;a href=&#34;https://frkl.io/blog/how-to-manage-your-dotfiles-with-freckles&#34;&gt;previous post in this series&lt;/a&gt; to understand what that does.&lt;/p&gt;

&lt;h3 id=&#34;data-centric-environment-management-using-freckelize&#34;&gt;Data-centric environment management using &lt;code&gt;freckelize&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This is a topic that deserves it&amp;rsquo;s own blog post. Until that is written: I think it makes sense, if at all possible, to keep metadata describing environment requirements with the data that is supposed to live in that environment. For the case of dotfiles, this means I think dotfile repositories should ideally contain, apart from the dotfiles itself, metadata about the applications that are required by the dotfiles, as well as other requirements (e.g. folders that need to exists, package managers that are used to install the required applications, details about how the config files itself should be setup, etc.).&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;freckles&lt;/em&gt; project provides three command line interfaces. The one that is interesting in this case is called &lt;code&gt;freckelize&lt;/code&gt;, and it&amp;rsquo;s written specifically to support and encourage data-driven environment management.&lt;/p&gt;

&lt;p&gt;In the following I&amp;rsquo;ll describe how to use &lt;code&gt;freckelize&lt;/code&gt;` to manage dotfiles and support the requirements I listed above.&lt;/p&gt;

&lt;h4 id=&#34;usage-profiles-1&#34;&gt;Usage &amp;lsquo;profiles&amp;rsquo;&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;freckelize&lt;/code&gt; works on folders containing structured data. A certain, pre-defined data structure is called a &amp;lsquo;profile&amp;rsquo;. For each such supported profile, &lt;code&gt;freckelize&lt;/code&gt; provides a so-called &amp;lsquo;&lt;a href=&#34;https://docs.freckles.io/en/latest/freckelize_command.html#adapters-profiles&#34;&gt;adapter&lt;/a&gt;&amp;rsquo;, which connects the structured data with an environment by executing tasks to prepare the environment to host that type of data. The adapter we are interested in is (not surprisingly) called &lt;a href=&#34;https://docs.freckles.io/en/latest/adapters/dotfiles.html&#34;&gt;&lt;em&gt;dotfiles&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I call a folder that contains structured data &amp;ndash; where the type of data is supported by &lt;code&gt;freckelize&lt;/code&gt; &amp;ndash; a &amp;lsquo;&lt;em&gt;freckle&lt;/em&gt;&amp;rsquo;. That&amp;rsquo;s a bit silly, I know, but I found it makes it easier to talk about all this.&lt;/p&gt;

&lt;h5 id=&#34;interlude-1-a-freckle-folder-without-any-metadata&#34;&gt;Interlude 1: a &amp;lsquo;&lt;em&gt;freckle&lt;/em&gt;&amp;rsquo; folder, without any metadata&lt;/h5&gt;

&lt;p&gt;By default, if no extra metadata is added to a folder, &lt;code&gt;freckelize&lt;/code&gt; considers the git repository it checks out to be the &lt;em&gt;freckle&lt;/em&gt;. So, if I use &lt;a href=&#34;https://github.com/makkus/dotfiles-test-simple-2&#34;&gt;this example dotfile repository&lt;/a&gt; with &lt;code&gt;freckelize&lt;/code&gt;, the command would look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;freckelize dotfiles -f gh:makkus/dotfiles-test-simple-2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;freckelize&lt;/code&gt; checks out the repository to &lt;code&gt;$HOME/freckles/dotfiles-test-simple-2&lt;/code&gt;, and as neither this folder nor any of it&amp;rsquo;s sub-folders contains a &lt;code&gt;freckelize&lt;/code&gt; metadata file (which would be named &lt;code&gt;.freckle&lt;/code&gt;) it will use the root of that local folder itself as the &lt;em&gt;freckle&lt;/em&gt;.&lt;/p&gt;

&lt;h5 id=&#34;interlude-2-one-or-several-freckle-folders-with-metadata&#34;&gt;Interlude 2:  one (or several) &amp;lsquo;&lt;em&gt;freckle&lt;/em&gt;&amp;rsquo; folders, with metadata&lt;/h5&gt;

&lt;p&gt;If &lt;code&gt;freckelize&lt;/code&gt; finds one or several files called &lt;code&gt;.freckle&lt;/code&gt; within the checked out git repository, it assumes those are the one(s) it is supposed to operate on, and it&amp;rsquo;ll not use the root of the git repository except if that also contains a &lt;code&gt;.freckle&lt;/code&gt; file. This is done so that in the majority of cases &lt;code&gt;freckelize&lt;/code&gt; does the right thing by default: if no &lt;code&gt;.freckle&lt;/code&gt; file exists, the user doesn&amp;rsquo;t even have to be aware of any conventions. If the user wants to do something out of the ordinary, they have to learn about the more advanced features of &lt;code&gt;freckelize&lt;/code&gt; anyway.&lt;/p&gt;

&lt;p&gt;So, if a folder contains one or more files named &lt;code&gt;.freckle&lt;/code&gt;, &lt;code&gt;freckelize&lt;/code&gt; will operate on all of those, using the parent folder of the &lt;code&gt;.freckle&lt;/code&gt; file as the &lt;em&gt;freckle&lt;/em&gt; folder. Those &lt;code&gt;.freckle&lt;/code&gt; files can be empty, or contain additional metadata which &lt;code&gt;freckelize&lt;/code&gt; will forward to the appropriate adapter.&lt;/p&gt;

&lt;h5 id=&#34;my-dotfiles-freckle-folders&#34;&gt;My dotfiles &amp;lsquo;freckle&amp;rsquo; folders&lt;/h5&gt;

&lt;p&gt;As I want to be able to use my dotfiles in several different usage scenarios, I have split up my dotfiles into 8 parts (as I&amp;rsquo;ve described above) by placing &lt;code&gt;.freckle&lt;/code&gt; files in the roots of the &amp;lsquo;profile&amp;rsquo; folders:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd ~/dotfiles

$ find|grep /.freckle$

./sec/.freckle
./terminal/dev/.freckle
./terminal/extra/.freckle
./terminal/minimal/.freckle
./x/dev/.freckle
./x/extra/.freckle
./x/i3-desktop/.freckle
./x/minimal/.freckle

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;freckelize&lt;/code&gt; let&amp;rsquo;s you limit which &lt;em&gt;freckle&lt;/em&gt; folders it uses with the &lt;code&gt;--include&lt;/code&gt; and &lt;code&gt;--exclude&lt;/code&gt; flags. Both of those can be used multiple times, and both of them look at the provided string, and in- or exclude freckle folders which full, absolute paths end with the provided string. So, for example, if I use &lt;code&gt;freckelize dotfiles --include terminal/minimal -f gh:makkus/dotfiles&lt;/code&gt;, it&amp;rsquo;ll use one &lt;em&gt;freckle&lt;/em&gt; folder:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotfiles/terminal/minimal
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If I use &lt;code&gt;--include minimal&lt;/code&gt; instead, I&amp;rsquo;ll have two matches:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotfiles/terminal/minimal
dotfiles/x/minimal
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or, if I specify &lt;code&gt;--include terminal/minimal --include terminal/extra&lt;/code&gt;, I&amp;rsquo;ll get:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotfiles/terminal/minimal
dotfiles/terminal/extra
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And so on, you get the idea. This lets me mix and match among all my usage profiles, and gives me fine-grained control which applications and configurations I want on a certain machine.&lt;/p&gt;

&lt;p&gt;One thing I should probably mention here is related to the usage of &lt;code&gt;stow&lt;/code&gt;: &lt;code&gt;stow&lt;/code&gt; often complains when you link into the same directory from different source &amp;lsquo;base&amp;rsquo; paths. You can get it to work well in such cases by adding an (empty) file called &lt;code&gt;.stow&lt;/code&gt; in the base of a &amp;lsquo;source&amp;rsquo; folder. Read more about this &lt;a href=&#34;https://www.gnu.org/software/stow/manual/stow.html#Multiple-Stow-Directories&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&#34;applications-1&#34;&gt;Applications&lt;/h4&gt;

&lt;p&gt;How to install applications that are related to the dotfiles we use is the topic of the previous blog post in this series, so just &lt;a href=&#34;https://frkl.io/blog/how-to-manage-your-dotfiles-with-freckles#freckelize&#34;&gt;head over there&lt;/a&gt; for details.&lt;/p&gt;

&lt;h4 id=&#34;additional-applications-and-alternative-package-managers&#34;&gt;Additional applications and alternative package managers&lt;/h4&gt;

&lt;p&gt;This is a huge can of worms, and although it sort of works now within &lt;em&gt;freckles&lt;/em&gt; for my needs, there is still quite a bit of work to be done to make the implementation cleaner, and to support more than the few package managers I implemented support for so far. If you want to help out and contribute support for a package manager (nodejs anyone?), let me know and I&amp;rsquo;ll explain the (few) things that need to be put in place.&lt;/p&gt;

&lt;p&gt;As I&amp;rsquo;ve mentioned, I use &lt;em&gt;nix&lt;/em&gt; for most of my user-space applications. Not for applications in my &amp;lsquo;&lt;strong&gt;minimal&lt;/strong&gt;&amp;rsquo; profile though, because I don&amp;rsquo;t want the additional overhead of having to install &lt;em&gt;nix&lt;/em&gt; for a few terminal appplications.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;frecklecute&lt;/code&gt; can (in most cases) figure out which package managers it needs to install automatically, so there is no need to provide a directive to instruct it to do so.&lt;/p&gt;

&lt;p&gt;As we&amp;rsquo;ve learned, &lt;code&gt;frecklecute&lt;/code&gt; takes notice of files named &lt;code&gt;.freckle&lt;/code&gt;. It uses them as marker files, to figure out which folders to process. But it also uses them to read additional user-provided metadata that is related to the &amp;lsquo;&lt;em&gt;freckle&lt;/em&gt;&amp;rsquo; folder and the adapter being used. To illustrate, this is how my &lt;code&gt;.freckle&lt;/code&gt; file for the &lt;strong&gt;terminal/extra&lt;/strong&gt; usage profile looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- dotfiles:
    pkg_mgr: auto
    packages:
      - direnv
      - gawk
      - pypy
      - pypy-dev
      - python-dev
      - python3-dev

- dotfiles:
    pkg_mgr: nix
    packages:
      - di
      - emacs
      - fasd-unstable
      - git-crypt
      - htop
      - imagemagick
      - mu
      - pandoc
      - password-store
      - silver-searcher
      - ranger
      - ripgrep
      - trash-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This instructs &lt;code&gt;frecklecute&lt;/code&gt; to use the default package manager on a system (&amp;lsquo;auto&amp;rsquo;) to install the first set of packages (the one starting with &amp;lsquo;direnv&amp;rsquo;), and &lt;em&gt;nix&lt;/em&gt; to install the other set. How to write those configuration files is a topic for another blog post, but it should be easy enough to see how it works in this case. When kicked off, &lt;code&gt;frecklecute&lt;/code&gt; will parse all the &lt;em&gt;freckle&lt;/em&gt; folder it encounters, then it&amp;rsquo;ll make a list of all packages to install and which package managers to use. If it comes across a package manager that isn&amp;rsquo;t installed on the machine yet, it&amp;rsquo;ll install it before attempting to install anything.&lt;/p&gt;

&lt;p&gt;Another example is the &lt;code&gt;.freckle&lt;/code&gt; file in my &lt;a href=&#34;https://github.com/makkus/dotfiles/tree/master/terminal/minimal&#34;&gt;&lt;strong&gt;terminal/minimal&lt;/strong&gt;&lt;/a&gt; profile:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- dotfiles:
    pkg_mgr: auto
    packages:
      - tree
      - zplug:
         pkg_mgr: git
         dest: ~/.zplug
         repo: https://github.com/zplug/zplug
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This combines two package managers under the same &lt;code&gt;dotfiles&lt;/code&gt; key. By default, all packages will inherit the package manager that is specified &amp;lsquo;adapter-wide&amp;rsquo;. But that can be overwritten for every package. In this case, we use &amp;lsquo;git&amp;rsquo; to install &lt;em&gt;zplug&lt;/em&gt;, a zsh plugin manaager (according to it&amp;rsquo;s &lt;a href=&#34;https://github.com/zplug/zplug#manually&#34;&gt;install instructions&lt;/a&gt;). Internally, &lt;code&gt;frecklecute&lt;/code&gt; uses the &lt;a href=&#34;http://docs.ansible.com/ansible/latest/git_module.html&#34;&gt;Ansible &lt;em&gt;git&lt;/em&gt; module&lt;/a&gt;, so we can use all options that are listed in this modules help page.&lt;/p&gt;

&lt;p&gt;If we want to use a non-default package manager for one of the &lt;a href=&#34;https://frkl.io/blog/how-to-manage-your-dotfiles-with-freckles#installing-your-applications&#34;&gt;folder-based applications&lt;/a&gt; installs, this can be done by adding a metadata file called &lt;code&gt;.package.freckle&lt;/code&gt; in the relevant dotfile folder, like I did in &lt;a href=&#34;https://github.com/makkus/dotfiles/blob/master/terminal/extra/tmux/.package.freckle&#34;&gt;the one that holds my &lt;em&gt;tmux config&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;pkg_mgr: nix
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;application-less-config-files-1&#34;&gt;&amp;lsquo;application-less&amp;rsquo; config files&lt;/h4&gt;

&lt;p&gt;In order to be able to have the configuration files that don&amp;rsquo;t relate directly to an applications (e.g. &lt;code&gt;.fonts&lt;/code&gt;) in the same repository as all your others, but not use them as package names when looking for applications, you can tell &lt;code&gt;frecklecute&lt;/code&gt; to omit a folder. To do that, all you need to do is create an (empty) marker file called &lt;code&gt;.no_stow.freckle&lt;/code&gt; in the folder you don&amp;rsquo;t want to be used as application name. Like I did for my &lt;code&gt;dotfiles/x/minimal/xkb&lt;/code&gt; folder which contains keyboard layouts:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; $ tree -a xkb
xkb
├── keymap
│   ├── filco
│   └── storm
├── .no_install.freckle
├── .no_stow.freckle
└── symbols
    ├── filco
    └── storm
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On a side-note: notice the &lt;code&gt;.no_install.freckle&lt;/code&gt; marker file. This does a similar thing than the &lt;code&gt;.no_stow.freckle&lt;/code&gt; one, it prevents &lt;code&gt;frecklecute&lt;/code&gt; from installing the (folder-name-based) application for that particular folder.&lt;/p&gt;

&lt;h4 id=&#34;encrypted-config-files-1&#34;&gt;Encrypted config files&lt;/h4&gt;

&lt;p&gt;There&amp;rsquo;s not all that much to tell about this, except that I put most of my semi-private files in the &lt;code&gt;sec&lt;/code&gt; usage profile and added their names to the &lt;a href=&#34;https://github.com/makkus/dotfiles/blob/master/.gitattributes&#34;&gt;.gitattributes&lt;/a&gt; file of the repository.&lt;/p&gt;

&lt;p&gt;Using this setup is a bit of a nightmare, because I can&amp;rsquo;t use any of the files (particularly the &lt;code&gt;gpg.conf&lt;/code&gt; one) before &amp;lsquo;unlocking&amp;rsquo; the repository. Which is kinda hard to do automatically as it needs a key passphrase, or my Yubikey pressed. Since I haven&amp;rsquo;t really figured out how to best handle this, I still do this part manually. And I don&amp;rsquo;t &amp;lsquo;stow&amp;rsquo; the `dotfiles/sec/gnupg folder automatically. I do, however, automatically import my gpg key and give it &amp;lsquo;ultimate&amp;rsquo; trust. For how that is done, read the next section:&lt;/p&gt;

&lt;h4 id=&#34;additional-provisioning-tasks-1&#34;&gt;Additional provisioning tasks&lt;/h4&gt;

&lt;p&gt;Because there are a lot of things that could potentially be required to setup a certain environment, it&amp;rsquo;s impossible to add &amp;lsquo;non-generic&amp;rsquo; functionality to the &amp;lsquo;dotfiles&amp;rsquo; adapter to satisfy a large enough percentage of such requirements to make sense.&lt;/p&gt;

&lt;p&gt;The &amp;lsquo;ansible-tasks&amp;rsquo; adapter to the rescue! This adapter is written for those cases that need generic task execution. This is a quite powerful feature, but also a dangerous one, as this can execute arbitrary commands. Be careful when you use this, and don&amp;rsquo;t use the &amp;lsquo;ansible-tasks&amp;rsquo; adapter without checking first what it does in every case.&lt;/p&gt;

&lt;p&gt;The way this adapter works is that it looks for a file called &lt;code&gt;.tasks.freckle&lt;/code&gt; in the root of the &lt;em&gt;freckle&lt;/em&gt; folder. If it finds it, and if it can parse it as yaml, it&amp;rsquo;ll execute all the tasks that it contains. The tasks itself are described using the &lt;a href=&#34;http://docs.ansible.com/ansible/latest/playbooks_intro.html#playbook-language-example&#34;&gt;&amp;lsquo;tasks&amp;rsquo;-part of the Ansible playbook format&lt;/a&gt;. It supports all the available official &lt;a href=&#34;http://docs.ansible.com/ansible/latest/list_of_all_modules.html&#34;&gt;Ansible modules&lt;/a&gt; as building blocks. A simple example is a list of a (single) task to ensure a few directories are present:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- name: &#39;creating folders in home dir&#39;
  file:
    path: &amp;quot;{{ item }}&amp;quot;
    state: directory
  with_items:
    - &amp;quot;~/.backups/zile&amp;quot;
    - &amp;quot;~/.emacs.d/cache/layouts&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or, a bit more involved, here&amp;rsquo;s how I import my gpg when initializing a new machine:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- name: ensure gnupg config dir has right permissions
  file:
    path: &amp;quot;~/.gnupg&amp;quot;
    mode: 0700
    state: directory

- name: importing gpg key stub
  command: &amp;quot;gpg --import {{ freckle_path }}/gnupg/.gnupg/gpg_public.key&amp;quot;
  args:
    creates: &amp;quot;~/.gnupg/trustdb.gpg&amp;quot;
  become: no

- name: setting gpg key trust to &#39;ultimate&#39;
  shell: &#39;echo -e &amp;quot;trust\n5\ny\n&amp;quot; | gpg --command-fd 0 --edit-key m@ilmark.us&#39;
  become: no

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This task list can re-use a few existing variables, &lt;code&gt;freckle_path&lt;/code&gt; being among them, and probably the most important one.&lt;/p&gt;

&lt;p&gt;Technical sidenote: In contrast to &lt;code&gt;freckelize&lt;/code&gt; adapters which can execute both &lt;em&gt;Ansible modules&lt;/em&gt; and &lt;em&gt;Ansible roles&lt;/em&gt;, this task list can only contain &lt;em&gt;Ansible module&lt;/em&gt;-tasks (for now, anyway).&lt;/p&gt;

&lt;h2 id=&#34;tldr&#34;&gt;tldr;&lt;/h2&gt;

&lt;p&gt;So, to sum it all up:&lt;/p&gt;

&lt;p&gt;If you want to use &lt;code&gt;freckelize&lt;/code&gt; to manage your dotfiles, including installation of applications and execution of additional provisioning tasks, you have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prepare one or more &lt;em&gt;dotfile&lt;/em&gt; repositories&lt;/li&gt;
&lt;li&gt;split up your dotfiles into &amp;lsquo;usage profiles&amp;rsquo; if you want to&lt;/li&gt;
&lt;li&gt;prepare (an optional)  &lt;code&gt;.freckle&lt;/code&gt; metadata file that contains additional applications which don&amp;rsquo;t need/have configurations&lt;/li&gt;
&lt;li&gt;prepare (an optional) &lt;code&gt;.tasks.freckle&lt;/code&gt; for every dotfile repository or usage profile that contains additional tasks to be executed&lt;/li&gt;
&lt;li&gt;log into the environment you want to add your dotfiles to&lt;/li&gt;
&lt;li&gt;execute &lt;code&gt;curl https://freckles.io | bash -s -- freckelize -f &amp;lt;dotfile_repo_url&amp;gt; dotfiles ansible-tasks&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;get a coffee, as this might take a while, depending on how many applications there are to install&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that&amp;rsquo;s it for &lt;em&gt;dotfiles&lt;/em&gt; and &lt;em&gt;freckles&lt;/em&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to manage your dotfiles with &#39;freckles&#39;</title>
      <link>https://frkl.io/blog/how-to-manage-your-dotfiles-with-freckles/</link>
      <pubDate>Tue, 24 Oct 2017 14:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/how-to-manage-your-dotfiles-with-freckles/</guid>
      <description>

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This was written for a previous version of &lt;a href=&#34;https://freckles.io&#34;&gt;freckles&lt;/a&gt;. The code/examples in here won&amp;rsquo;t work anymore.&lt;/p&gt;

&lt;p&gt;This is part two of a three-part series about managing dotfiles with &lt;em&gt;freckles&lt;/em&gt;. The &lt;a href=&#34;https://frkl.io/blog/managing-dotfiles&#34;&gt;first part&lt;/a&gt; explained what dotfiles are, why one might want to manage them, and how to do that by hand. This one here will show you how to do the same thing using &lt;a href=&#34;https://github.com/makkus/freckles&#34;&gt;freckles&lt;/a&gt;, and &lt;a href=&#34;https://frkl.io/blog/how-to-manage-my-dotfiles-with-freckles&#34;&gt;the last one&lt;/a&gt; will show how to use &lt;em&gt;freckles&lt;/em&gt; with a more involved setup (mine).&lt;/p&gt;

&lt;p&gt;If you haven&amp;rsquo;t &amp;ndash; or just can&amp;rsquo;t be bothered to &amp;ndash; read my &lt;a href=&#34;https://frkl.io/blog/so-i-made-this-thing&#34;&gt;introductory post about &lt;em&gt;freckles&lt;/em&gt;&lt;/a&gt;: &lt;em&gt;freckles&lt;/em&gt; is a configuration management tool to help you setup your working environment with as little fuss and configuration as necessary.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;freckles&lt;/em&gt; comes with three different command-line applications, all with slightly different goals. &lt;code&gt;freckles&lt;/code&gt; itself, &lt;code&gt;frecklecute&lt;/code&gt;, and, for our purpose the most relevant:&lt;/p&gt;

&lt;h2 id=&#34;freckelize&#34;&gt;&lt;em&gt;freckelize&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;freckelize&lt;/code&gt;&amp;rsquo;s main goal is to support a data-centric configuration management approach, in your working environment. It supports plugins, so-called &amp;lsquo;adapters&amp;rsquo;, which help prepare an environment for certain types of data. One such type of data is a dotfiles folder laid out in the way described below (the relevant adapter is named &amp;lsquo;dotfiles&amp;rsquo;, unsurprisingly).&lt;/p&gt;

&lt;h3 id=&#34;checking-out-your-dotfiles-repo-and-stowing-your-config&#34;&gt;checking out your dotfiles repo, and &amp;lsquo;stowing&amp;rsquo; your config&lt;/h3&gt;

&lt;p&gt;To recap, in the &lt;a href=&#34;https://frkl.io/blog/managing-dotfiles&#34;&gt;previous post&lt;/a&gt; I described a simple folder structure for configuration files which can easily be used with &lt;code&gt;stow&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotfiles
├── bash
│   ├── .bashrc
│   └── .profile
├── git
│   └── .gitconfig
├── i3
│   ├── .config
│   │   ├── i3
│   │   │   └── config
├── zile
│   └── .zile
└── zsh
    ├── .zprofile
    ├── .zshenv
    └── .zshrc

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you created your dotfiles repository similar to this, and uploaded it to github, you can already use &lt;em&gt;freckles&lt;/em&gt; to initialize a new machine:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ curl https://freckles.io | bash -s -- freckelize dotfiles -f gh:&amp;lt;your github username&amp;gt;/&amp;lt;your dotfiles repo name&amp;gt; --no-install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is designed to be as easy to remember as such a curl/bash command can possibly be, and to do as much as makes sense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it bootstraps the &lt;em&gt;freckles&lt;/em&gt; python package from pypi including it&amp;rsquo;s dependencies, then runs &lt;code&gt;freckelize&lt;/code&gt; (which comes with it)&lt;/li&gt;
&lt;li&gt;it might or might not ask for your &amp;lsquo;sudo&amp;rsquo; password, which the underlying &lt;a href=&#34;https://ansible.com&#34;&gt;Ansible&lt;/a&gt; application might need to install dependencies (like for example &lt;code&gt;git&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;it expands the &lt;code&gt;gh:&amp;lt;xxx&amp;gt;/&amp;lt;xxx&amp;gt;&lt;/code&gt; url to a proper github one&lt;/li&gt;
&lt;li&gt;it uses &lt;code&gt;git&lt;/code&gt; to check out your dotfiles repository (to &lt;code&gt;$HOME/freckles/&amp;lt;repo_name&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;it &lt;code&gt;stow&lt;/code&gt;s all the configuration files in the dotfile repositories sub-folders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How this bootstrap and &lt;code&gt;freckelize&lt;/code&gt; work in detail is explained in the &lt;a href=&#34;https://docs.freckles.io&#34;&gt;freckles documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;installing-your-applications&#34;&gt;installing your applications&lt;/h3&gt;

&lt;p&gt;You might have noticed the &lt;code&gt;--no-install&lt;/code&gt; flag at the end of the above command. This tells &lt;code&gt;freckelize&lt;/code&gt; (more exactly, &lt;code&gt;freckelize&lt;/code&gt;s &amp;lsquo;dotfiles&amp;rsquo; adapter) to not execute the &amp;lsquo;install&amp;rsquo; step, which it would do by default.&lt;/p&gt;

&lt;p&gt;Most of the time, if you have have configuration for an app, you want that app to be installed. And most of the time that application&amp;rsquo;s package name is the same as the one you&amp;rsquo;ll have used as sub-folder name in your dotfiles repository (e.g. &lt;code&gt;i3&lt;/code&gt;, &lt;code&gt;zile&lt;/code&gt;, &amp;hellip;). So, why not use that folder name as the metadata to make sure the application a set of configuration files is associated with is installed? This is what the &lt;em&gt;freckelize&lt;/em&gt; dotfile adapter does by default. So let&amp;rsquo;s run the above command again, without &lt;code&gt;--no-install&lt;/code&gt;, and without the &lt;code&gt;curl&lt;/code&gt; part since &lt;em&gt;freckles&lt;/em&gt; is already installed:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ source ~/.profile     # in case you haven&#39;t logged out and logged in again, to pick up the PATH freckles is installed in
$ freckelize dotfiles -f gh:&amp;lt;your github username&amp;gt;/&amp;lt;your dotfiles repo name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will not only stow all your configuration files, but also install packages named after sub-folders in your dotfiles repository, using the system package manager.&lt;/p&gt;

&lt;h3 id=&#34;installing-additional-applications-that-don-t-have-configurations&#34;&gt;installing (additional) applications that don&amp;rsquo;t have configurations&lt;/h3&gt;

&lt;p&gt;Now, most of the time you&amp;rsquo;ll want additional applications to be installed, ones that don&amp;rsquo;t have or need configuration files, or where you are just happy with the default config.&lt;/p&gt;

&lt;p&gt;This is easy to do as well with &lt;em&gt;freckelize&lt;/em&gt;, but we need to create an extra metadata file to be able to tell &lt;em&gt;freckelize&lt;/em&gt; which applications to install. &lt;em&gt;freckelize&lt;/em&gt; can do more than just install and manage &lt;em&gt;dotfiles&lt;/em&gt;, which is a topic for other blog posts, but it has one file it always looks up: &lt;code&gt;.freckle&lt;/code&gt; in the root of the repository you point it to. So, let&amp;rsquo;s add a few &amp;lsquo;non-configuration&amp;rsquo; applications (using yaml syntax):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;dotfiles:
  packages:
    - htop
    - tree
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As we are using the &lt;code&gt;freckelize&lt;/code&gt; &lt;em&gt;dotfiles&lt;/em&gt; adapter, we&amp;rsquo;ll need to put details about it&amp;rsquo;s execution under the &lt;code&gt;dotfiles&lt;/code&gt; key, otherwise it wouldn&amp;rsquo;t be picked up. The &lt;em&gt;dotfiles&lt;/em&gt; adapter understands keys other than &lt;code&gt;packages&lt;/code&gt;, which I&amp;rsquo;ll say more about below, and in the next blog post in this series. Or you can of course check out the &lt;a href=&#34;https://docs.freckles.io/en/latest/adapters/dotfiles.html&#34;&gt;dotfiles adapter documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve prepared an example repository that contains configuration for the &lt;em&gt;fish&lt;/em&gt; shell, as well as the &lt;em&gt;zile&lt;/em&gt; editor, and which uses the above &lt;code&gt;.freckle&lt;/code&gt; file, here: &lt;a href=&#34;https://github.com/makkus/dotfiles-test-simple&#34;&gt;https://github.com/makkus/dotfiles-test-simple&lt;/a&gt;. To apply that dotfile repository to your machine would look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-consloe&#34;&gt;$ freckelize dotfiles -f gh:makkus/dotfiles-test-simple

# using repo(s):

 - gh:makkus/dotfiles-test-simple
     -&amp;gt; remote: &#39;https://github.com/makkus/dotfiles-test-simple.git&#39;
     -&amp;gt; local: &#39;/home/vagrant/freckles/dotfiles-test-simple.git&#39;

# starting ansible run...

* starting tasks (on &#39;localhost&#39;)...
 * starting to process freckle(s)...
   - checking out freckle(s) =&amp;gt;
       - https://github.com/makkus/dotfiles-test-simple.git =&amp;gt; ok (changed)
   - starting adapter &#39;dotfiles&#39; =&amp;gt; ok (no change)
   - starting dotfile adapter execution =&amp;gt; ok (no change)
   - install dotfile folders packages =&amp;gt;
       - zile (using: apt) =&amp;gt; ok (changed)
       - fish (using: apt) =&amp;gt; ok (changed)
   - install dotfiles packages-list packages =&amp;gt;
       - htop (using: apt) =&amp;gt; ok (changed)
       - tree (using: apt) =&amp;gt; ok (changed)
   - installing stow =&amp;gt;
       - stow (using: apt) =&amp;gt; ok (changed)
   - stowing folders =&amp;gt;
       - zile =&amp;gt; ok (changed)
       - fish =&amp;gt; ok (changed)
   =&amp;gt; ok (changed)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To check the created symlinks we can:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ ls -lah ~
total 57M
drwxr-xr-x 8 vagrant vagrant 4.0K Oct 24 09:58 .
drwxr-xr-x 3 root    root    4.0K Jun 19 23:27 ..
drwx------ 3 vagrant vagrant 4.0K Oct 24 09:56 .ansible
-rw-r--r-- 1 vagrant vagrant  220 Jun 19 23:27 .bash_logout
-rw-r--r-- 1 vagrant vagrant 3.5K Jun 19 23:27 .bashrc
drwx------ 3 vagrant vagrant 4.0K Oct 24 09:55 .cache
lrwxrwxrwx 1 vagrant vagrant   42 Oct 24 09:58 .config -&amp;gt; freckles/dotfiles-test-simple/fish/.config
drwxr-xr-x 3 vagrant vagrant 4.0K Oct 24 09:58 freckles
drwxr-xr-x 5 vagrant root    4.0K Oct 24 09:57 .local
-rw-r--r-- 1 vagrant vagrant  809 Oct 24 09:56 .profile
drwx------ 2 vagrant vagrant 4.0K Oct 24 09:54 .ssh
-rw------- 1 vagrant vagrant   60 Oct 24 09:57 .Xauthority
lrwxrwxrwx 1 vagrant vagrant   40 Oct 24 09:58 .zile -&amp;gt; freckles/dotfiles-test-simple/zile/.zile
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As I&amp;rsquo;ve mentioned before, &lt;code&gt;freckelize&lt;/code&gt; can actually do a bit more, and it can be configured much more fine-grained, for example to install packages using other package-managers (git, conda, nix, &amp;hellip;). You can specify different package names for an application. You can also run a set of additional tasks that create folders, import gpg keys, or do whatever else you might need done. I&amp;rsquo;ll write about all this in the &lt;a href=&#34;https://frkl.io/blog/how-to-manage-my-dotfiles-with-freckles&#34;&gt;last post of this series&lt;/a&gt;, using my own setup as an example.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Managing dotfiles</title>
      <link>https://frkl.io/blog/managing-dotfiles/</link>
      <pubDate>Tue, 24 Oct 2017 13:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/managing-dotfiles/</guid>
      <description>

&lt;p&gt;This is part one of a three-part series about managing dotfiles with &lt;em&gt;freckles&lt;/em&gt;. This one covers the basics about what dotfiles are, why managing them might or might not make sense, and how to do it manually. &lt;a href=&#34;https://frkl.io/blog/how-to-manage-your-dotfiles-with-freckles&#34;&gt;The second one&lt;/a&gt; shows how to use a tool &lt;a href=&#34;https://frkl.io/blog/so-i-made-this-thing&#34;&gt;I wrote&lt;/a&gt; &amp;ndash; &lt;a href=&#34;https://github.com/makkus/freckles&#34;&gt;&lt;em&gt;freckles&lt;/em&gt;&lt;/a&gt; &amp;ndash; to do the same thing with (arguably) less effort. &lt;a href=&#34;https://frkl.io/blog/how-to-manage-my-dotfiles-with-freckles&#34;&gt;The last post&lt;/a&gt; will cover how I manage my own dotfiles using &lt;em&gt;freckles&lt;/em&gt;, as I&amp;rsquo;ve got a fairly involved setup which shows how to use all the more advanced options of &lt;em&gt;freckles&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&#34;dotfiles-and-why-you-might-want-to-manage-them&#34;&gt;&amp;lsquo;&lt;em&gt;dotfiles&lt;/em&gt;&amp;rsquo;, and why you might want to manage them&lt;/h2&gt;

&lt;p&gt;&amp;lsquo;&lt;em&gt;dotfiles&lt;/em&gt;&amp;rsquo; are configuration (text-) files, named so because on UNIX systems they usually start with a &amp;ldquo; . &amp;ldquo;. If you are mostly using Windows, and/or GUI applications, this all might not really apply to you, as configurations are often stored in a non-text format, in a registry, or in other really weird places. If you use Linux or Mac OS X (or more recently, the Ubunty subsystem on Windows), and the command-line, you&amp;rsquo;ll have probably come across them though.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;dotfiles&lt;/em&gt; usually live directly under your home directory or, quite often nowadays, in a folder called &lt;code&gt;.config&lt;/code&gt; in your home directory. Sometimes applications have a single configuration file, sometimes they have a whole sub-folder of them, and sometimes they give you the choice, depending on how far you want to go customizing the apps behaviour.&lt;/p&gt;

&lt;p&gt;As well as there not being a really standardized location where &lt;em&gt;dotfiles&lt;/em&gt; can be found, there&amp;rsquo;s also no &amp;lsquo;one&amp;rsquo; format for them. Some of them are &lt;em&gt;ini&lt;/em&gt;-style key/value files, some of them are &lt;em&gt;yaml&lt;/em&gt;, or &lt;em&gt;json&lt;/em&gt;, or &amp;ndash; god forbid &amp;ndash; &lt;em&gt;xml&lt;/em&gt;. Some of them are even &lt;em&gt;python code&lt;/em&gt; or &lt;em&gt;bash scripts&lt;/em&gt;. All depends on the application they belong to.&lt;/p&gt;

&lt;p&gt;The more you use certain applications, the more you&amp;rsquo;ll find yourself working on it&amp;rsquo;s configuration to better support your way of working, or your use-cases. That also means that you spend a non-trivial amount of time on customizing your workstation experience, time you probably don&amp;rsquo;t want to loose if you loose your laptop, or even just the filesystem where the configuration is stored. Which is why a lot of people store their &lt;em&gt;dotfiles&lt;/em&gt; in a version control system. Mostly git, since that is where most of their other work lives as well. This also gives you the advantage of tracking the history of the changes you made to them, so if something goes wrong, looking at the git history might give you some clue as to what changed.&lt;/p&gt;

&lt;h2 id=&#34;different-ways-of-managing-your-dotfiles&#34;&gt;different ways of managing your dotfiles&lt;/h2&gt;

&lt;p&gt;There are already several interesting tools out there to manage dotfiles, for example &lt;a href=&#34;https://github.com/anishathalye/dotbot&#34;&gt;dotbot&lt;/a&gt;, &lt;a href=&#34;https://github.com/technicalpickles/homesick&#34;&gt;homesick&lt;/a&gt;, &lt;a href=&#34;https://github.com/thoughtbot/rcm&#34;&gt;rcm&lt;/a&gt;, or &lt;a href=&#34;https://github.com/TheLocehiliosan/yadm&#34;&gt;yadm&lt;/a&gt;. You can even use &lt;a href=&#34;https://medium.com/@rawkode/managing-dotfiles-with-saltstack-eb600867073e&#34;&gt;saltstack&lt;/a&gt; (which is seriously cool and which I&amp;rsquo;d probably have used if anyone had told me about it before I was almost finished writing &lt;em&gt;freckles&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;So, after you get an idea how to use &lt;em&gt;freckles&lt;/em&gt; to manage dotfiles, you might want to check out some of those and see whether maybe they are a better fit for your setup. Workstation setups and configurations are very personal and individual things, which is probably why there hasn&amp;rsquo;t emerged a commonly used, &amp;lsquo;best-practice&amp;rsquo; kind of tool or structure that almost everybody uses.&lt;/p&gt;

&lt;p&gt;In addition to those alternative helper tools, there are usually two strategies (as far as I can tell) to use git to store your dotfiles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.atlassian.com/blog/2016/02/best-way-to-store-dotfiles-git-bare-repo/&#34;&gt;a bare git repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://alexpearce.me/2016/02/managing-dotfiles-with-stow/&#34;&gt;using gnu stow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my opinion, both approaches have their advantages, so, again, I&amp;rsquo;d recommend reading up on both of them. For my workflow, as much as I like the idea, the &amp;lsquo;bare git repo&amp;rsquo; approach is too inflexible to be of enough value, which is why I choose to use &amp;lsquo;stow&amp;rsquo;. Which is also the method &lt;em&gt;freckles&lt;/em&gt; uses. I&amp;rsquo;ll cover the details of those more advanced use-cases in the third installment of this series, but if you have a fairly straight-forward setup, using a bare git repository might very well be the better solution.&lt;/p&gt;

&lt;h2 id=&#34;dotfiles-folder-structure&#34;&gt;dotfiles folder structure&lt;/h2&gt;

&lt;p&gt;As the &amp;lsquo;stow&amp;rsquo; method symbolically links your configuration files into where they need to be, you have a certain degree of flexibility as to how you organize your dotfiles folder. For most use-cases, it&amp;rsquo;ll look something like this though:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotfiles
├── bash
│   ├── .bashrc
│   └── .profile
├── git
│   └── .gitconfig
├── i3
│   ├── .config
│   │   ├── i3
│   │   │   └── config
├── zile
│   └── .zile
└── zsh
    ├── .zprofile
    ├── .zshenv
    └── .zshrc

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is probably the approach that gets recommended the most. It&amp;rsquo;s a neat and tidy structure as each application gets it&amp;rsquo;s own sub-folder. Within that sub-folder we re-create the folder structure the application expectes, and as it would look like from the root of the home directory. In this example, most configuration files live directly under &lt;code&gt;$HOME&lt;/code&gt; (&lt;code&gt;.bashrc&lt;/code&gt;, &lt;code&gt;.zile&lt;/code&gt;, etc.), except for the &lt;code&gt;i3&lt;/code&gt; one, which has it&amp;rsquo;s configuration file (named &lt;code&gt;config&lt;/code&gt;) in the folder &lt;code&gt;$HOME/.config/i3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In a setup like this, this is how you&amp;rsquo;d execute &lt;code&gt;stow&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ stow -d &amp;lt;dotfiles_dir&amp;gt; -t $HOME -S *
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will link the contents of each of the sub-directories into &lt;code&gt;$HOME&lt;/code&gt;, using the relative paths to them we created earlier (if necessary):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ ls -lah ~/.bashrc
lrwxrwxrwx 1 markus markus 38 Okt 22 16:38 /home/markus/.bashrc -&amp;gt; dotfiles/bash/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;stow&lt;/code&gt; is quite smart about how it does the linking, and how it treats existing (sub-)directories, check out its &lt;a href=&#34;https://www.gnu.org/software/stow/manual/stow.html&#34;&gt;manual&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2 id=&#34;setting-up-a-newly-installed-machine&#34;&gt;setting up a newly installed machine&lt;/h2&gt;

&lt;p&gt;In order to manually configure a new machine using the configuration you created and uploaded to github, you&amp;rsquo;ll have to do something like this (let&amp;rsquo;s assume we are using an Ubuntu box):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ sudo apt install git
...
$ git clone https://github.com/makkkus/dotfiles.git ~/dotfiles
...
$ sudo apt install stow
...
$ stow -d &amp;lt;dotfiles_dir&amp;gt; -t $HOME -S *
...
$ sudo apt install i3 zile zsh &amp;lt;all other applications you use&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You could probably do the app installs in one command, and &lt;code&gt;git&lt;/code&gt; is most likely already installed. So, this doesn&amp;rsquo;t look too bad and could be scripted fairly easily, especially if you don&amp;rsquo;t have a lot of applications to install, and you always use the same operating system or distribution (as different OS&amp;rsquo;s or distributions have sometimes different package names for the same application).&lt;/p&gt;

&lt;p&gt;So, as long as your setup is as simple as my example here, I&amp;rsquo;d recommend stop reading here, and just do it like this (or, as mentioned above, use a bare git repo instead).&lt;/p&gt;

&lt;p&gt;But, if you have done that, and at some stage you find (as I did) that this eventually, with a growing amount of configuration folders and files and applications, gets a bit un-organized; or you&amp;rsquo;d like to just record new applications to install into a text file which gets read the next time you re-install a new machine; or you use more than one platform, and the difference between those always screws with your script, or makes it more complex than you like it to be; or you only want to use a sub-set of your application on certain targets; or you just think (like I do), that having to enter more than one line or write a script for something so trivial is annoying; &amp;ndash; if any of those things apply to you, check out the next two installments of this series &lt;a href=&#34;https://frkl.io/blog/how-to-manage-your-dotfiles-with-freckles&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;https://frkl.io/blog/how-to-manage-my-dotfiles-with-freckles&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>So, I made this ..thing</title>
      <link>https://frkl.io/blog/so-i-made-this-thing/</link>
      <pubDate>Wed, 18 Oct 2017 14:00:00 +0200</pubDate>
      
      <guid>https://frkl.io/blog/so-i-made-this-thing/</guid>
      <description>

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This was written for a previous version of &lt;a href=&#34;https://freckles.io&#34;&gt;freckles&lt;/a&gt;. The code/examples in here won&amp;rsquo;t work anymore.&lt;/p&gt;

&lt;p&gt;It was one of those &amp;lsquo;scratch-your-own-itch&amp;rsquo;-situations, I suppose. Only, I really didn&amp;rsquo;t want to scratch that particular itch myself.&lt;/p&gt;

&lt;p&gt;For one, because I knew exactly how long it&amp;rsquo;d take me to write this if I wanted to do it properly. And I really thought it is something so obvious that sooner or later somebody will build (something like) it, and all I have to do is go on Reddit, moan a bit about how it&amp;rsquo;s bloated, and (obviously) written in the wrong language. But I&amp;rsquo;ll use it anyway, you can thank me later.&lt;/p&gt;

&lt;p&gt;It looks like I was wrong though, and it&amp;rsquo;s either not obvious at all, or other people were playing the same waiting game as me. Or, of course, it is just a really stupid idea. Not yet counting that one out either. Whatever the reason, I waited for a few years, and nobody scratched my itch. So, eventually I gave in and wrote that &amp;hellip;thing. Named the thing &amp;lsquo;&lt;strong&gt;freckles&lt;/strong&gt;&amp;rsquo;. Uploaded it to Github: &lt;a href=&#34;https://github.com/makkus/freckles&#34;&gt;https://github.com/makkus/freckles&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although it&amp;rsquo;s not quite finished yet, I consider it usable now.&lt;/p&gt;

&lt;p&gt;What am I talking about? What is this thing?? Glad you asked! I&amp;rsquo;m not 100% happy with that description, but basically:&lt;/p&gt;

&lt;h1 id=&#34;the-thing-quick-and-easy-local-configuration-management&#34;&gt;The thing: (quick and easy) &lt;em&gt;&amp;lsquo;local&amp;rsquo;&lt;/em&gt; configuration management&lt;/h1&gt;

&lt;p&gt;I&amp;rsquo;m not going to write about what exactly made me create &lt;em&gt;freckles&lt;/em&gt; (might do that in a later blog post if anybody is interested) and how it works in detail (there&amp;rsquo;s &lt;a href=&#34;https://docs.freckles.io&#34;&gt;https://docs.freckles.io&lt;/a&gt; for that). I should, however, probably explain what &lt;em&gt;configuration management&lt;/em&gt; is, for those of you who don&amp;rsquo;t know.&lt;/p&gt;

&lt;h1 id=&#34;yes-what-is-this-configuration-management-you-speak-of&#34;&gt;Yes, what is this configuration management you speak of?&lt;/h1&gt;

&lt;p&gt;If you are familiar with &lt;a href=&#34;https://ansible.com&#34;&gt;Ansible&lt;/a&gt;, &lt;a href=&#34;https://puppet.com&#34;&gt;puppet&lt;/a&gt;, &lt;a href=&#34;https://www.chef.io&#34;&gt;chef&lt;/a&gt;, or &lt;a href=&#34;https://saltstack.com&#34;&gt;salt&lt;/a&gt;, you know about configuration management, and why (for the most part) it is a good idea. If not: in short, configuration management gives you a way to describe a machine/server and the services and applications it runs. Either in code, or a configuration format like &lt;em&gt;json&lt;/em&gt; or &lt;em&gt;yaml&lt;/em&gt;. Then it takes that configuration and applies it to a machine, removing the need for you to setup the machine manually, as well as guaranteeing that the machine is always setup the same way, even (or especially) after a re-install. As a bonus, often times you can use the configuration itself as a sort of always-up-to-date documentation on how your infrastructure is set up. Much more organized and parse-able than, say, a bash script.&lt;/p&gt;

&lt;p&gt;Because of the overhead that comes with configuration management frameworks, using them is usually restricted to situations where the infrastructure to be controlled is deemed to cross a certain threshold of&amp;hellip; let&amp;rsquo;s call it &amp;lsquo;importance&amp;rsquo;. While for production services or other business-relevant systems this threshold is often crossed even for single servers or services, this is not usually the case for the physical (or virtual) machines we developers (or somesuch) use when going about whatever we go about. There are exceptions of course, but spending the time to learn about, and then setting up a system like that is not always worth it.&lt;/p&gt;

&lt;h1 id=&#34;cue-freckles&#34;&gt;Cue, &amp;lsquo;freckles&amp;rsquo;&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;freckles&lt;/em&gt; tries to change that effort/value equation by making it easier &amp;ndash;and faster &amp;ndash; to practice configuration management, at least in local development environments. I do think there&amp;rsquo;s a lot of developers time to be saved, to be used on actual development, rather than all the annoying stuff around it (like, for example, setting up and configuring webservers). Plus, a bit of good practice never hurt anybody, right?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;freckles&lt;/em&gt; comes with (so far) three command-line interfaces (&lt;code&gt;freckles&lt;/code&gt; itself, &lt;code&gt;frecklecute&lt;/code&gt; and &lt;code&gt;freckelize&lt;/code&gt;) which all do slightly different things. They all are designed to primarlily do cnfiguration management on single boxes. Physical or virtual ones, local or remote. Where you have &amp;lsquo;root&amp;rsquo; access, or you don&amp;rsquo;t. Whichever distribution of Linux, or Mac OS X.&lt;/p&gt;

&lt;p&gt;Basically any type of box you want to get into a certain state. Unlike other configuration management systems, &lt;em&gt;freckles&lt;/em&gt; doesn&amp;rsquo;t need any infrastructure around it because everything runs on the box that needs the state change. That means, in turn, there is the overhead (mainly time and hard-disk space) of having to get it onto every one of those machines, instead of having a single &amp;lsquo;controller&amp;rsquo; which distributes configuration changes across the network. So, it&amp;rsquo;s not a good fit for medium- or large-sized infrastructures.&lt;/p&gt;

&lt;p&gt;Internally, &lt;em&gt;freckles&lt;/em&gt; uses &lt;a href=&#34;https://ansible.com&#34;&gt;Ansible&lt;/a&gt; to apply state changes to the machine it is working on. &lt;em&gt;Ansible&lt;/em&gt; is a comparably light-weight and easy to use configuration management framework, and it comes with hundreds of so-called &lt;a href=&#34;http://docs.ansible.com/ansible/latest/list_of_all_modules.html&#34;&gt;modules&lt;/a&gt; and &lt;a href=&#34;https://galaxy.ansible.com/&#34;&gt;roles&lt;/a&gt;, which are easy-to use, pre-made building blocks to change state on a machine. And which can all be used with &lt;em&gt;freckles&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are a few areas where &lt;em&gt;freckles&lt;/em&gt; does things differently than &lt;em&gt;Ansible&lt;/em&gt; (and also other configuration management systems), or focuses on slightly different things:&lt;/p&gt;

&lt;h2 id=&#34;transparent-bootstrap&#34;&gt;(Transparent) bootstrap&lt;/h2&gt;

&lt;p&gt;Although (or because) you have to get &lt;em&gt;freckles&lt;/em&gt; on every machine you want to get configured, I made it quite easy to do so, using the &lt;a href=&#34;https://github.com/makkus/inaugurate&#34;&gt;inaugurate&lt;/a&gt; bootstrap script (which is a spin-off of the &lt;em&gt;freckles&lt;/em&gt; project itself). Running bash scripts directly from the internet is a slightly controversial topic, and I don&amp;rsquo;t really want to discuss this here. I&amp;rsquo;ve written about what that means, why it&amp;rsquo;s not the real problem, and how to make it work in a secure way for you in a few other places though: &lt;a href=&#34;https://docs.freckles.io/en/latest/trust.html&#34;&gt;here&lt;/a&gt;, &lt;a href=&#34;https://github.com/makkus/inaugurate#is-this-secure&#34;&gt;here&lt;/a&gt;, and &lt;a href=&#34;https://docs.freckles.io/en/latest/bootstrap.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Basically, the first time you execute one of &lt;em&gt;freckles&lt;/em&gt; command-line interfaces, you do it via &lt;code&gt;curl&lt;/code&gt; (or &lt;code&gt;wget&lt;/code&gt;), like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl https://freckles.io | bash -s -- freckles &amp;lt;freckles_arguments&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will install &lt;em&gt;freckles&lt;/em&gt; in your home directory (more details &lt;a href=&#34;https://github.com/makkus/inaugurate#how-does-this-work-what-does-it-do&#34;&gt;here&lt;/a&gt;), and also executes it for it&amp;rsquo;s first run. It&amp;rsquo;ll add itself to your &lt;code&gt;PATH&lt;/code&gt; in &lt;code&gt;$HOME/.profile&lt;/code&gt;, so once you either sourced that (&lt;code&gt;source ~/.profile&lt;/code&gt;), or logged out of your current session and logged in again you can use it directly (using the same command you&amp;rsquo;d have used after the &lt;code&gt;... | bash -s --&lt;/code&gt; in the example above).&lt;/p&gt;

&lt;p&gt;Depending on the situation you might only need to execute &lt;code&gt;freckles&lt;/code&gt; (or it&amp;rsquo;s companion interfaces &lt;code&gt;freckelize&lt;/code&gt; or &lt;code&gt;frecklecute&lt;/code&gt;) once. If that&amp;rsquo;s the case, you can delete the folder it was installed into straight away after execution, by setting an environment variable (e.g. to save some space in a Docker container):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl https://freckles.io | SELF_DESTRUCT=true bash -s -- freckles &amp;lt;freckles_arguments&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;one-line-execution&#34;&gt;One-line execution&lt;/h2&gt;

&lt;p&gt;Related to bootstrapping, &lt;em&gt;freckles&lt;/em&gt; tries to let you execute a configuration run for a machine in one command. Before that works, you might have to prepare roles and/or execution scripts, and host those somewhere online, or you can re-use pre-made, shared ones (in which case you&amp;rsquo;ll have to be mindful that this could be a security issue). But once that is done, you can apply the same configuration on different machines, platforms, distribution versions, with said one-line execution, always using the same line. Provided, of course, you made sure to support all those different platforms etc in your roles. Configure once, run everywhere, sorta.&lt;/p&gt;

&lt;p&gt;For example, in order to get all &lt;a href=&#34;https://github.com/makkus/dotfiles&#34;&gt;my dotfiles&lt;/a&gt; (&amp;lsquo;dotfiles&amp;rsquo; are configuration files) installed on a new machine, as well as all applications installed that are referenced in them, all I have to execute is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;curl https://freckles.io | bash -s -- freckelize dotfiles -f gh:makkus/dotfiles

# or, if freckles is alrady installed

freckelize dotfiles -f gh:makkus/dotfiles
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(on a sidenote: &lt;code&gt;gh:makkus/dotfiles&lt;/code&gt; is an abbreviation that &lt;em&gt;freckles&lt;/em&gt; automatically expands to &lt;code&gt;https://github.com/makkus/dotfiles.git&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll talk a bit more about &lt;code&gt;freckelize&lt;/code&gt; and &lt;em&gt;dotfiles&lt;/em&gt; &lt;a href=&#34;#data-centric-configuration...&#34;&gt;below&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another example would be to setup a machine that runs a webserver to host/redirect readthedocs.io documentation via your own domain and https, as explained &lt;a href=&#34;http://docs.readthedocs.io/en/latest/alternate_domains.html&#34;&gt;in the readthedocs documentation&lt;/a&gt; (weird example, I know &amp;ndash; but I had to do that recently for obvious reasons):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;curl https://freckles.io | bash -s -- frecklecute gh:makkus/freckles/examples/readthedocsforwarding.yml

# or, if freckles is alrady installed, and the script is available locally

frecklecute /home/markus/frecklecutables/readthedocsforwarding.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the content of the &lt;code&gt;readthedocsforwarding.yml&lt;/code&gt; file, read the next part:&lt;/p&gt;

&lt;h2 id=&#34;one-file-configuration&#34;&gt;One-file configuration&lt;/h2&gt;

&lt;p&gt;One of the slight annoyances I feel when using &lt;em&gt;Ansible&lt;/em&gt; to run a few tasks and/or roles on my local machine is that I always have to touch quite a few files. There&amp;rsquo;s the inventory, then vars files, and the playbook file itself. And you might or might not have to download roles you use manually. For simple cases, I always wanted to be able to describe everything in just one file, kinda like a &lt;em&gt;Dockerfile&lt;/em&gt;, but (much) more powerful. Or like a bash script, but more readable, and less time-consuming to create.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;frecklecute&lt;/code&gt;, which comes as part of &lt;em&gt;freckles&lt;/em&gt; can do just that. As you&amp;rsquo;ve seen in the above example, it can use either local or remote (yaml) files (which I call &lt;em&gt;frecklecutables&lt;/em&gt;) to execute some tasks. Details about how this works can be found &lt;a href=&#34;https://docs.freckles.io/en/latest/frecklecute_command.html&#34;&gt;here&lt;/a&gt;, but I&amp;rsquo;ll show you the content of the &lt;code&gt;readthedocsforwarding.yml&lt;/code&gt; file to give you an idea:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;tasks:

  - install: fail2ban

  - thefinn93.letsencrypt:
      letsencrypt_webroot_path: /var/www/html
      letsencrypt_email: makkus@frkl.io
      letsencrypt_cert_domains:
        - docs.freckles.io
      letsencrypt_renewal_command_args: &#39;--renew-hook &amp;quot;systemctl restart nginx&amp;quot;&#39;

  - geerlingguy.nginx:
      nginx_remove_default_vhost: true
      nginx_vhosts:
       - listen: &amp;quot;80&amp;quot;
         server_name: &amp;quot;docs.freckles.io&amp;quot;
         return: &amp;quot;301 https://docs.freckles.io$request_uri&amp;quot;
       - listen: &amp;quot;443 ssl http2&amp;quot;
         server_name: &amp;quot;docs.freckles.io&amp;quot;
         state: &amp;quot;present&amp;quot;
         extra_parameters: |
            location / {
               proxy_pass https://freckles.readthedocs.io:443;
               proxy_set_header Host $http_host;
               proxy_set_header X-Forwarded-Proto https;
               proxy_set_header X-Real-IP $remote_addr;
               proxy_set_header X-Scheme $scheme;
               proxy_set_header X-RTD-SLUG freckles;
               proxy_connect_timeout 10s;
               proxy_read_timeout 20s;
            }
            ssl_certificate      /etc/letsencrypt/live/docs.freckles.io/fullchain.pem;
            ssl_certificate_key  /etc/letsencrypt/live/docs.freckles.io/privkey.pem;
            ssl_protocols        TLSv1.1 TLSv1.2;
            ssl_ciphers          HIGH:!aNULL:!MD5;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you have used &lt;em&gt;Ansible&lt;/em&gt; before, this should look familiar to you. This script first downloads all the external roles it needs, after that it installs the &lt;em&gt;fail2ban&lt;/em&gt; package (because that&amp;rsquo;s always a good idea for a server), then uses the &lt;a href=&#34;https://galaxy.ansible.com/thefinn93/letsencrypt/&#34;&gt;thefinn93.letsencrypt ansible role&lt;/a&gt; to retrieve a certificate from the &lt;em&gt;let&amp;rsquo;s encrypt&lt;/em&gt; CA (which will only work if executed on a machine matching the specified hostname, obviously). Once that it done it&amp;rsquo;ll  create a cron job to always re-new that certificate in time, and install the nginx webserver (using &lt;a href=&#34;https://galaxy.ansible.com/geerlingguy/nginx/&#34;&gt;this role&lt;/a&gt;) including the site configuration that sets up the forwarding to &lt;em&gt;readthedocs.io&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;All that can obviously also be done with &lt;em&gt;Ansible&lt;/em&gt; itself. And it should probably be, in case of a larger infrastructure and, you know, &amp;lsquo;production&amp;rsquo;. But for a single server, and prototyping or development &lt;em&gt;frecklecute&lt;/em&gt; might be an adequate solution. One thing to mention is that &lt;em&gt;freckles&lt;/em&gt; does not support all features of &lt;em&gt;Ansible&lt;/em&gt; directly (like for example the &lt;code&gt;when&lt;/code&gt; directive). This is partly deliberate to keep those &lt;em&gt;frecklecutables&lt;/em&gt; simple and readable. And partly due to time constraints on my part. Not having those features is not really a problem though, because I recommend to always write an &lt;a href=&#34;https://docs.ansible.com/ansible/2.4/playbooks_reuse_roles.html&#34;&gt;Ansible role&lt;/a&gt; once the task to be executed becomes non-trivial. Then include that role in the &lt;em&gt;frecklecutable&lt;/em&gt; as a task item. Much cleaner that way.&lt;/p&gt;

&lt;p&gt;A nice thing about all this is that you can use &lt;em&gt;frecklecute&lt;/em&gt; and this &lt;em&gt;frecklecutable&lt;/em&gt; in either a Docker container build process, a Vagrant box (well, probably not &lt;em&gt;that&lt;/em&gt; file since it needs an outside internet connection and a proper hostname), or a VPS on whichever VPS provider you use.&lt;/p&gt;

&lt;h2 id=&#34;data-centric-environment-management&#34;&gt;Data-centric environment management&lt;/h2&gt;

&lt;p&gt;While working on &lt;em&gt;freckles&lt;/em&gt; I realized that in a lot of cases the metadata that is required to setup a working environment is already present in the structure or content of the data or code that is supposed to be used in that working environment (or can be very easily added to that environment in the form of a metadata file).&lt;/p&gt;

&lt;p&gt;This is often obvious for programming projects, where build tools expect for example a file called &lt;code&gt;setup.py&lt;/code&gt; (similar for other programming languages). But it can be used in a lot more cases. For example, the &lt;em&gt;dotfiles&lt;/em&gt; I mentioned earlier: if you structure them in a way that the configuration files for an application are in a folder that is named after the package name of the application itself, then you can use that information to install the application while at the same time putting the configuration files in the locations they need to be (e.g. via symlinks).&lt;/p&gt;

&lt;p&gt;Above I&amp;rsquo;ve shown you how I initialize a new machine with my &lt;em&gt;dotfiles&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;freckelize dotfiles -f gh:makkus/dotfiles
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;dotfiles&lt;/code&gt; part is referencing a so-called &lt;em&gt;freckelize adapter&lt;/em&gt;, which &amp;ndash; in the &lt;code&gt;dotfiles&lt;/code&gt; case &amp;ndash; is shipped with &lt;em&gt;freckles&lt;/em&gt;. Again, I&amp;rsquo;ll not go into detail how exactly this works (go &lt;a href=&#34;https://docs.freckles.io/en/latest/freckelize_command.html&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;https://docs.freckles.io/en/latest/adapters/dotfiles.html&#34;&gt;here&lt;/a&gt; if you are interested). But, in short, such an adapter expects data of a certain shape, and executes steps to prepare a host machine to be able to host that particular data profile.
In this example it checks out my configuration files and links them to all the right places and installs all applications I usually work with. On any (physical or virtual) machine I happen to need them.&lt;/p&gt;

&lt;p&gt;Another example is this very webpage you are reading at the moment. In order to setup a development environment for it on my workstation, I execute:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;freckelize vagrant-dev -f gh:makkus/freckles_website
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will checkout the source code of this site, setup &lt;a href=&#34;https://www.vagrantup.com&#34;&gt;Vagrant&lt;/a&gt; if not already installed, as well as other potential requirements which might be specified in that repository (e.g. Virtualbox, Vagrant plugins).&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&#34;https://github.com/makkus/freckles_website/blob/master/Vagrantfile&#34;&gt;Vagrantfile&lt;/a&gt; of this project I again use &lt;code&gt;freckelize&lt;/code&gt; to bootstrap an environemt that contains nginx, php, and the &lt;a href=&#34;https://getgrav.org&#34;&gt;grav cms&lt;/a&gt;, in the Vagrant box to be created:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;wget -O - https://freckles.io | sudo bash -s -- freckelize -r gh:makkus/frecklets grav -f /vagrant/ --port 8280 --nginx-user vagrant
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In order for all that to work I had to prepare an &lt;a href=&#34;https://github.com/makkus/grav_ansible&#34;&gt;Ansible role&lt;/a&gt; and a &lt;a href=&#34;https://github.com/makkus/grav_ansible/tree/master/freckle_adapter&#34;&gt;freckelize adapter&lt;/a&gt; to setup a machine to be able to host a &lt;a href=&#34;https://getgrav.org&#34;&gt;grav&lt;/a&gt; webpage, and add them, as well as roles to setup nginx and php, to a &lt;a href=&#34;https://github.com/makkus/frecklets&#34;&gt;git repository&lt;/a&gt;. Once that is done, I can re-use those for every &lt;em&gt;grav&lt;/em&gt; website I&amp;rsquo;ll create in the future (and so can you, if you decide I and the other role creators involved are trustworthy enough). I&amp;rsquo;ll probably write another blog-post about how this works in details later.&lt;/p&gt;

&lt;p&gt;As is the case with the &lt;em&gt;readthedocs&lt;/em&gt; example above, that setup can easily be used in a lot of different situations or technologies (Docker, Vagrant, LXC, physical host&amp;hellip;).&lt;/p&gt;

&lt;h2 id=&#34;scripting&#34;&gt;Scripting&lt;/h2&gt;

&lt;p&gt;In addition to all this, &lt;em&gt;freckles&lt;/em&gt; can also be used to quickly write commandline scripts that use &lt;code&gt;frecklecute&lt;/code&gt; as their sort of &amp;lsquo;interpreter&amp;rsquo;. Again, not going into any detail here, instead, check out &lt;a href=&#34;https://docs.freckles.io/en/latest/frecklecute_command.html#frecklecutables-in-your-path&#34;&gt;this link&lt;/a&gt;, and &lt;a href=&#34;https://docs.freckles.io/en/latest/writing_frecklecutables.html&#34;&gt;this link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A quick example script to create a folder using the &amp;lsquo;file&amp;rsquo; &lt;em&gt;Ansible module&lt;/em&gt;, and user-input for the folder to create would be:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;#! /usr/bin/env frecklecute
doc:
  help: create a folder
args:
  path:
    help: the folder path
    default: ~/cool_folder
tasks:
  - file:
      state: directory
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Saved in a file called &amp;lsquo;folder-create&amp;rsquo;, chmod&amp;rsquo;ed to be executable, and either put in your PATH or executed directly would look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ create-folder --help
Usage: frecklecute ./create-folder [OPTIONS]

  create a folder

Options:
  --path TEXT  the folder path
  --help       Show this message and exit.

  For more information about frecklecute and the freckles project, please
  visit: https://github.com/makkus/freckles

$ create-folder --path ~/now-that-is-a-folder-created-in-an-interesting-way

* starting tasks (on &#39;localhost&#39;)...
 * starting custom tasks:
     * file... ok (changed)
   =&amp;gt; ok (changed)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or upload it to github and execute it like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ frecklecute gh:makkus/freckles/examples/create-folder --path ~/a-folder-created-from-a-remote-frecklecutable

* starting tasks (on &#39;localhost&#39;)...
 * starting custom tasks:
     * file... ok (changed)
   =&amp;gt; ok (changed)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously, this all is a tad overkill just to create a folder. But as I&amp;rsquo;ve mentioned before, this can be used with all the &lt;em&gt;Ansible modules&lt;/em&gt; and &lt;em&gt;roles&lt;/em&gt; available. Galaxy is the limit&amp;hellip;&lt;/p&gt;

&lt;p&gt;And, if you really want to go all out, you can even combine this with the online bootstraping of &lt;em&gt;freckles&lt;/em&gt; which means neither &lt;em&gt;freckles&lt;/em&gt; nor your &lt;em&gt;frecklecutable&lt;/em&gt; need to be on a machine to be able to run it. Only &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt;. And you don&amp;rsquo;t need any root permissions either, as long as the &lt;em&gt;Ansible roles&lt;/em&gt; or &lt;em&gt;modules&lt;/em&gt; you use don&amp;rsquo;t require it. I think that&amp;rsquo;s quite cool. And probably pretty dangerous too, in the hand of fools. Good thing there are hardly any fools in this world!&lt;/p&gt;

&lt;h2 id=&#34;direct-ansible-role-or-module-execution&#34;&gt;Direct Ansible role or module execution&lt;/h2&gt;

&lt;p&gt;And, for extra credit, and those of us who only want to quickly execute an Ansible role, on a machine without anything useful installed (again, except for &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34;&gt;$ curl https://freckles.io | bash -s -- frecklecute ansible-task --become --task-name mongrelion.docker
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Not going to explain what that does, as it should be obvious by now (hint: &lt;code&gt;mongrelion.docker&lt;/code&gt; is an &lt;em&gt;Ansible role&lt;/em&gt; that installs &amp;hellip; well). You get the idea&amp;hellip;&lt;/p&gt;

&lt;h1 id=&#34;use-cases&#34;&gt;Use-cases&lt;/h1&gt;

&lt;p&gt;Here is a random list of other use cases &lt;em&gt;freckles&lt;/em&gt; can be used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;after installing a new (physical or virtual) machine, quickly install and configure it with the applications you commonly use, by letting &lt;em&gt;freckelize&lt;/em&gt; download and process a remote (or local) dotfile/configuration repository (adapter documentation: &lt;a href=&#34;https://docs.freckles.io/en/latest/adapters/dotfiles.html&#34;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;setup the source code of the projects you are working on, including their dependencies, on your machine (e.g. &lt;a href=&#34;https://docs.freckles.io/en/latest/adapters/python-dev.html&#34;&gt;Python projects&lt;/a&gt;, or (generic) &lt;a href=&#34;https://docs.freckles.io/en/latest/adapters/vagrant-dev.html&#34;&gt;projects that use Vagrant&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;quickly write a short script to install/update some of your own (non-packaged) applications (e.g. &lt;em&gt;freckles&lt;/em&gt; uses &lt;code&gt;frecklecute&lt;/code&gt; to &lt;a href=&#34;https://github.com/makkus/freckles/blob/master/freckles/external/frecklecutables/update-freckles&#34;&gt;update itself&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;ensure you and your team-mates use the same setup of a certain development environment&lt;/li&gt;
&lt;li&gt;quickly &lt;a href=&#34;https://docs.freckles.io/en/latest/frecklecutables/ansible-task.html&#34;&gt;execute a &amp;lsquo;one-off&amp;rsquo; Ansible task or role&lt;/a&gt; (e.g. to install and configure &lt;a href=&#34;https://galaxy.ansible.com/mongrelion/docker/&#34;&gt;Docker&lt;/a&gt;, or &lt;a href=&#34;https://galaxy.ansible.com/geerlingguy/nginx/&#34;&gt;nginx&lt;/a&gt;, etc.), without having to install Ansible itself manually (more info: &lt;a href=&#34;https://docs.freckles.io/en/latest/frecklecutables/ansible-task.html&#34;&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;write easy to read and understand deployment scripts, which can also be used for documentation or education purposes (e.g. in a blog post), and which can be used in combination with &lt;em&gt;inaugurate&lt;/em&gt; to create &amp;lsquo;no-requirement&amp;rsquo; bootstrap scripts&lt;/li&gt;
&lt;li&gt;create scriptlets that are easy to share and execute, to init new (development or other) projects from templates&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, most things you can imagine which change the state of your machine/filesystem from a relatively &amp;lsquo;useless&amp;rsquo;, to a more &amp;lsquo;useful&amp;rsquo; state. The definition of &amp;lsquo;useless&amp;rsquo; and &amp;lsquo;useful&amp;rsquo; is up to you, of course.&lt;/p&gt;

&lt;h1 id=&#34;where-to-from-here&#34;&gt;Where to, from here?&lt;/h1&gt;

&lt;p&gt;Not sure, really.&lt;/p&gt;

&lt;p&gt;The main selling point for &lt;em&gt;freckles&lt;/em&gt; are the many &lt;em&gt;Ansible roles&lt;/em&gt; and &lt;em&gt;modules&lt;/em&gt; it can use (as well as, of course, Ansible itself). One idea I have is to create a repository of &amp;lsquo;curated&amp;rsquo; roles, which I want to call the &amp;lsquo;&lt;a href=&#34;https://github.com/freckles-io/ark&#34;&gt;Ark&lt;/a&gt;&amp;rsquo; (&lt;strong&gt;A&lt;/strong&gt;nsible &lt;strong&gt;R&lt;/strong&gt;ole somewordstartingwith-&lt;strong&gt;K&lt;/strong&gt;-maybeKiosk), and which will contain only one role per thing to do or install, and one role only. &lt;em&gt;Ansible Galaxy&lt;/em&gt; is great, but I find it a bit hard at times to find the best role for what I try to do, and the platform I try to do it on. I think, in a lot of cases it&amp;rsquo;d be better to work together on commonly agreed upon &amp;ldquo;main&amp;rdquo; role for a problem, and improve it, than to create a new role that is targeted only on a certain platform, or version of software. There is a lot of that happening already, just not in a very structured way. As far as I know, anyway.&lt;/p&gt;

&lt;p&gt;Roles in that repository would have a maintainer, would have tests, would work for as many platforms as possible, and would be continually improved upon. Haven&amp;rsquo;t really had time to think this through, and create a list of requirements. Ideally, I wouldn&amp;rsquo;t have to do that on my own though, and other people who also see value in this and are keen to collaborate on it would join in.&lt;/p&gt;

&lt;p&gt;As for &lt;em&gt;freckles&lt;/em&gt; itself, I still have quite a few ideas about features and improvements, but I reckon I&amp;rsquo;ll wait and see whether and how much uptake it sees in the next few weeks/months. Then decide whether to spend more time on it and for example give it proper unit-testing, logging and more documentation. Or whether to write the thing I actually wanted to write when my annoyance of something like &lt;em&gt;freckles&lt;/em&gt; not existing became stronger than my reluctance to write it myself. Or whether to actually start earning money again. Bah, stupid money&amp;hellip;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>About</title>
      <link>https://frkl.io/about/</link>
      <pubDate>Tue, 27 Jun 2017 17:39:21 -0700</pubDate>
      
      <guid>https://frkl.io/about/</guid>
      <description>&lt;p&gt;&lt;strong&gt;frkl&lt;/strong&gt; is my small software and consulting enterprise.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s an experiment. I&amp;rsquo;m trying to figure out whether it&amp;rsquo;s possible to work on the (slightly weird) software I want to exist in the world and also earn a living.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
