<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>A weblog by Yaroslav de la Peña Smirnov</title>
	<link href="https://www.yaroslavps.com/weblog/feed.xml/" rel="self" type="application/atom+xml"/>
	<link href="https://www.yaroslavps.com/"/>
	<generator uri="https://www.getzola.org/">Zola</generator>
	<updated>2023-02-10T22:38:08+00:00</updated>
	<id>https://www.yaroslavps.com/weblog/feed.xml/</id>
	<entry xml:lang="en">
		<title>Introduction to Generic Netlink, or How to Talk with the Linux Kernel</title>
		<published>2023-02-10T22:38:08+00:00</published>
		<updated>2023-02-10T22:38:08+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/genl-intro/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/genl-intro/</id>
		<content type="html">&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;genl-intro&#x2F;genl-tux.png&quot; alt=&quot;Tux has got some mail!&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Are you writing some code in kernel-space and want to communicate with it from
the comfort of user-space? You are not writing kernel code, but want to talk
with the Linux kernel? Serve yourself some good java (the good hot kind, not the
Oracle one), make yourself comfortable and read ahead!&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;I recently got myself into programming in the Linux Kernel, more specifically
kernel space modules, and one of the APIs that I had to study was Generic
Netlink. As is usual with most Linux Kernel APIs the documentation, outside of
sometimes fairly well commented code, is a bit lacking and&#x2F;or old.&lt;&#x2F;p&gt;
&lt;p&gt;Hence why I decided to make a little example for myself on how to use Generic
Netlink for kernel-user space communications, and an introductory guide using
the aforementioned example for my colleagues and any other person interested in
using Generic Netlink but not knowing where to start.&lt;&#x2F;p&gt;
&lt;p&gt;This guide covers the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Registering Generic Netlink families in kernel.&lt;&#x2F;li&gt;
&lt;li&gt;Registering Generic Netlink operations and handling them in kernel.&lt;&#x2F;li&gt;
&lt;li&gt;Registering Generic Netlink multicast groups in kernel.&lt;&#x2F;li&gt;
&lt;li&gt;Sending &quot;events&quot; through Generic Netlink from kernel.&lt;&#x2F;li&gt;
&lt;li&gt;Connecting to Generic Netlink from a user program.&lt;&#x2F;li&gt;
&lt;li&gt;Resolving Generic Netlink families and multicast groups from a user program.&lt;&#x2F;li&gt;
&lt;li&gt;Sending a message to a Generic Netlink family from a user program.&lt;&#x2F;li&gt;
&lt;li&gt;Subscribing to a Generic Netlink multicast group from a user program.&lt;&#x2F;li&gt;
&lt;li&gt;Listening for Generic Netlink messages from a user program.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;what-is-netlink&quot;&gt;What is Netlink?&lt;&#x2F;h2&gt;
&lt;p&gt;Netlink is a socket domain created with the task of providing IPC for the Linux
Kernel, especially kernel&amp;lt;-&amp;gt;user IPC. Netlink was created initially with the
intention of replacing the aging ioctl() interface, by providing a more flexible
way of communicating between kernel and user programs.&lt;&#x2F;p&gt;
&lt;p&gt;Netlink communication happens over standard sockets using the &lt;code&gt;AF_NETLINK&lt;&#x2F;code&gt;
domain. Nonetheless, on the user land side of things, libraries exist that
provide a more convenient way of using the Netlink interface, such as libnl&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;That said, new Netlink families aren&#x27;t being created anymore and new code
doesn&#x27;t use Netlink directly. The classic use of Netlink is relegated to already
existing families such as &lt;code&gt;NETLINK_ROUTE&lt;&#x2F;code&gt;, &lt;code&gt;NETLINK_SELINUX&lt;&#x2F;code&gt;, etc. The main
problem with Netlink is that it uses static allocation of IDs which are limited
to 32 unique families, which greatly limits its users and may cause conflicts
with out-of-tree modules.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;presenting-generic-netlink&quot;&gt;Presenting Generic Netlink&lt;&#x2F;h2&gt;
&lt;p&gt;Generic Netlink was created to fix the deficiencies of Netlink as well as
bringing some quality of life improvements. It is not a separate socket domain
though, it&#x27;s more of an extension of Netlink. In fact, it is a Netlink family —
&lt;code&gt;NETLINK_GENERIC&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Generic Netlink has been around since 2005 so it is a well established interface
for kernel&amp;lt;-&amp;gt;userspace IPC. Some notable users of Generic Netlink include
subsystems such as 802.11, ACPI, Wireguard, among others.&lt;&#x2F;p&gt;
&lt;p&gt;The main features that Generic Netlink brings to the table are dynamic family
registration, introspection and a simplified kernel API. This tutorial is
focused specifically on Generic Netlink, since it&#x27;s the standard way of
communicating with the kernel in ways that are more sophisticated than a simple
sysfs file.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;genl-intro&#x2F;01-diagram.png&quot; alt=&quot;Generic Netlink bus diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Generic Netlink bus diagram&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;h2 id=&quot;some-theory&quot;&gt;Some theory&lt;&#x2F;h2&gt;
&lt;p&gt;As I&#x27;ve already mentioned, Netlink works over the usual BSD sockets. A Netlink
message always starts with a Netlink header, followed by a protocol header, that
is in the case of Generic Netlink, the Generic Netlink header.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;netlink-messages&quot;&gt;Netlink messages&lt;&#x2F;h3&gt;
&lt;p&gt;The headers look like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;genl-intro&#x2F;02-nlmsghdr.png&quot; alt=&quot;Netlink header&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Netlink Header&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;genl-intro&#x2F;03-genlmsghdr.png&quot; alt=&quot;Generic Netlink header&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Generic Netlink Header&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;Or as described by the following C structures:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;nlmsghdr {
&lt;&#x2F;span&gt;&lt;span&gt;	__u32		nlmsg_len;
&lt;&#x2F;span&gt;&lt;span&gt;	__u16		nlmsg_type;
&lt;&#x2F;span&gt;&lt;span&gt;	__u16		nlmsg_flags;
&lt;&#x2F;span&gt;&lt;span&gt;	__u32		nlmsg_seq;
&lt;&#x2F;span&gt;&lt;span&gt;	__u32		nlmsg_pid;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;genlmsghdr {
&lt;&#x2F;span&gt;&lt;span&gt;	__u8	cmd;
&lt;&#x2F;span&gt;&lt;span&gt;	__u8	version;
&lt;&#x2F;span&gt;&lt;span&gt;	__u16	reserved;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Netlink header fields meaning:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Length — the length of the whole message, including headers.&lt;&#x2F;li&gt;
&lt;li&gt;Type — the Netlink family ID, in our case Generic Netlink.&lt;&#x2F;li&gt;
&lt;li&gt;Flags — a do or dump; more on that later.&lt;&#x2F;li&gt;
&lt;li&gt;Sequence — sequence number; also more on that later.&lt;&#x2F;li&gt;
&lt;li&gt;Port ID — set to 0, since we are sending from kernel.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;and for Generic Netlink:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Command: operation identifier as defined by the Generic Netlink family.&lt;&#x2F;li&gt;
&lt;li&gt;Version: the version of the Generic Netlink family protocol.&lt;&#x2F;li&gt;
&lt;li&gt;Reserved: as its name implies ¯\&lt;em&gt;(ツ)&lt;&#x2F;em&gt;&#x2F;¯.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Most of the fields are pretty straight forward, and the header is not usually
filled manually by the Netlink user. Some of the information contained in the
headers is provided by the user through the API when calling the different
functions. Some of that information are things like the flags and sequence
numbers.&lt;&#x2F;p&gt;
&lt;p&gt;There are three types of message operations that are usually performed over a
Netlink socket:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A do operation&lt;&#x2F;li&gt;
&lt;li&gt;A dump operation&lt;&#x2F;li&gt;
&lt;li&gt;And multicast messages, or asynchronous notifications.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There are many different ways of sending messages over Netlink, but these are
the most used in Generic Netlink.&lt;&#x2F;p&gt;
&lt;p&gt;A do operation is a single action kind of operation in which the user program
sends the message and receives a reply that could be an acknowledgment or error
message, or maybe even a message with some information.&lt;&#x2F;p&gt;
&lt;p&gt;A dump operation is one for (duh) dumping information, usually more than fits in
one message. The user program also sends a message but receives multiple reply
message until received a &lt;code&gt;NLMSG_DONE&lt;&#x2F;code&gt; message that signals the end of the dump.&lt;&#x2F;p&gt;
&lt;p&gt;Whether an operation is a do or a dump is set using the flags field:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NLM_F_REQUEST | NLM_F_ACK&lt;&#x2F;code&gt; for do.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP&lt;&#x2F;code&gt; for dump.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Now the third type, the multicast messages, are used for sending notifications
to the users that are subscribed to them via the generic netlink multicast
group.&lt;&#x2F;p&gt;
&lt;p&gt;As we saw, there&#x27;s also a sequence number field in the Netlink header. However,
unlike in other protocols, Netlink doesn&#x27;t manipulate or enforce the sequence
number itself. It&#x27;s provided as a way to help keep track of messages and
replies. In practice, the user program would increase the sequence number with
each message sent, and the kernel module would send the reply(ies) with the same
sequence as the command message. Multicast message are usually sent with a
sequence number of 0.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;message-payload&quot;&gt;Message payload&lt;&#x2F;h3&gt;
&lt;p&gt;Netlink provides a system of attributes to encode data with information such as
type and length. The use of attributes allows for validation of data and for a
supposedly easy way to extend protocols without breaking backward compatibility.&lt;&#x2F;p&gt;
&lt;p&gt;You can also encode your own types, such as a struct in a single attribute.
However, the use of Netlink attributes for each field is encouraged.&lt;&#x2F;p&gt;
&lt;p&gt;The attributes are encoded in LTV format and are padded such that each attribute
begins at an offset that is a multiple of 4 bytes. The length fields, both in
the message header and attribute, always include the header, but not the
padding.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;genl-intro&#x2F;04-nlattr.png&quot; alt=&quot;Netlink attribute diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Netlink attribute diagram&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;The attributes in a Netlink, and hence Generic Netlink, message are not
necessarily added always in the same order, which is why they should be walked
and parsed.&lt;&#x2F;p&gt;
&lt;p&gt;Netlink provides for a way to validate that a message is correctly formatted
using so called &quot;attribute validation policies&quot;, represented by &lt;code&gt;struct nla_policy&lt;&#x2F;code&gt;. I do find it a bit strange that the structure is not exposed to
user space and hence validation seems to be performed by default only on the
kernel side. It can also be done on user space and libnl also provides its own
&lt;code&gt;struct nla_policy&lt;&#x2F;code&gt; but it differs from the kernel one which means you basically
have to do duplicate work to validate the attributes on both sides.&lt;&#x2F;p&gt;
&lt;p&gt;The types of messages and operations are defined by the so called Netlink
commands. A command correlates to one message type, and also might correlate to
one op(eration).&lt;&#x2F;p&gt;
&lt;p&gt;Each command or message type can have or use one or more attributes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;families&quot;&gt;Families&lt;&#x2F;h3&gt;
&lt;p&gt;I have already mentioned families in this text and in different contexts.
Unfortunately, as is common in the world of computer programming, things
sometimes aren&#x27;t named in the very best way hence we end up with situations like
this one.&lt;&#x2F;p&gt;
&lt;p&gt;Sockets have families, of which we use the &lt;code&gt;AF_NETLINK&lt;&#x2F;code&gt;. Netlink also has
families, of which there are only 32, and no more are planned or should be
introduced to the Linux kernel; the family we use is &lt;code&gt;NETLINK_GENERIC&lt;&#x2F;code&gt;. Last but
not least, Generic Netlink also has families, although these are dynamically
registered and a whopping total of 1024 can be registered at a single time.&lt;&#x2F;p&gt;
&lt;p&gt;Generic Netlink families are identified by a string, such as &quot;nl80211&quot;, for
example. Since the families are registered dynamically, that means that their ID
can change from one computer to another or even one boot to another, so we need
to resolve them before we can send messages to a family.&lt;&#x2F;p&gt;
&lt;p&gt;Generic Netlink in itself provides a single statically allocated family called
&lt;code&gt;nlctrl&lt;&#x2F;code&gt; which provides with a command to resolve said families. It also
provides since not long ago a way for introspecting operations and exposing
policies to user space, but we are not going to go into detail on this in this
tutorial.&lt;&#x2F;p&gt;
&lt;p&gt;One more thing of note is that a single Generic Netlink socket is not bound to
any one family. A Generic Netlink socket can talk to any family at any time, it
just needs to provide the family ID when sending the message, by using the type
field as we saw earlier.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;multicast-groups&quot;&gt;Multicast groups&lt;&#x2F;h3&gt;
&lt;p&gt;There are some message that we would like to send asynchronously to user
programs in order to notify them of some events, or just communicate information
as it becomes available. This is where multicast groups come in.&lt;&#x2F;p&gt;
&lt;p&gt;Generic Netlink multicast groups, just like families, are dynamically registered
with a string name and receiving a numeric ID upon registration. In other words,
they must also be resolved before being to subscribe to them. Once subscribed to
a multicast group, the user program will receive all message sent to the group.&lt;&#x2F;p&gt;
&lt;p&gt;In order to avoid mixing sequence numbers with unicast messages and to make
handling easier, it is recommended to use a different socket for multicast
messages.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-our-hands-dirty&quot;&gt;Getting our hands dirty&lt;&#x2F;h2&gt;
&lt;p&gt;There&#x27;s much more about Generic Netlink and especially classic Netlink, but
those were the most important concepts to know about when working with Generic
Netlink. That said, it&#x27;s not very interesting just knowing about something, we
are here for the action after all.&lt;&#x2F;p&gt;
&lt;p&gt;I have made an example of using Generic Netlink that consists of two parts. A
kernel module, and a userland program.&lt;&#x2F;p&gt;
&lt;p&gt;The kernel module provides a single generic netlink operation and a multicast
group. The message structure is the same for the do op and the multicast
notification. The first reads a string message, prints it to the kernel log, and
sends its own message back; and the second sends a notification upon reading a
message from sysfs, echoing it.&lt;&#x2F;p&gt;
&lt;p&gt;The user space program connects to Generic Netlink, subscribes to the multicast
group, sends a message to our family and prints out the received messages.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ll be explaining them step by step with code listings in this article. The
full source code for both parts can be found at
&lt;a href=&quot;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;genltest&#x2F;&quot;&gt;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;genltest&#x2F;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-land-of-the-kernel&quot;&gt;The land of the Kernel&lt;&#x2F;h3&gt;
&lt;p&gt;Using Generic Netlink from kernel space is pretty straightforward. All we need
to start using it is to include a single header in our file, &lt;code&gt;net&#x2F;genetlink.h&lt;&#x2F;code&gt;.
In total all the headers that we need to start working with our example are as
follows:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;linux&#x2F;module.h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;net&#x2F;genetlink.h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We&#x27;ll need some definitions and enumerations that will be shared between kernel
space and user space, we&#x27;ll put them in a header file that we&#x27;ll call
&lt;code&gt;genltest.h&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;GENLTEST_GENL_NAME &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;genltest&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;GENLTEST_GENL_VERSION &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;GENLTEST_MC_GRP_NAME &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;mcgrp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Attributes *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;genltest_attrs {
&lt;&#x2F;span&gt;&lt;span&gt;	GENLTEST_A_UNSPEC,
&lt;&#x2F;span&gt;&lt;span&gt;	GENLTEST_A_MSG,
&lt;&#x2F;span&gt;&lt;span&gt;	__GENLTEST_A_MAX,
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;GENLTEST_A_MAX (__GENLTEST_A_MAX &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Commands *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;genltest_cmds {
&lt;&#x2F;span&gt;&lt;span&gt;	GENLTEST_CMD_UNSPEC,
&lt;&#x2F;span&gt;&lt;span&gt;	GENLTEST_CMD_ECHO,
&lt;&#x2F;span&gt;&lt;span&gt;	__GENLTEST_CMD_MAX,
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;GENLTEST_CMD_MAX (__GENLTEST_CMD_MAX &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There we defined the name of our family, our protocol version, our multicast
group name, the attributes that we will use in our messages and our commands.&lt;&#x2F;p&gt;
&lt;p&gt;Back in our kernel code, we make a validation policy for our &quot;echo&quot; command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Attribute validation policy for our echo command *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nla_policy echo_pol[GENLTEST_A_MAX &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	[GENLTEST_A_MSG] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{ .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; NLA_NUL_STRING },
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Make an array with our Generic Netlink operations:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Operations for our Generic Netlink family *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; genl_ops genl_ops[] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	{
&lt;&#x2F;span&gt;&lt;span&gt;		.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;cmd	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; GENLTEST_CMD_ECHO,
&lt;&#x2F;span&gt;&lt;span&gt;		.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;policy &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; echo_pol,
&lt;&#x2F;span&gt;&lt;span&gt;		.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;doit	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; echo_doit,
&lt;&#x2F;span&gt;&lt;span&gt;	 },
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Similarly an array with our multicast groups:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Multicast groups for our family *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static const &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; genl_multicast_group genl_mcgrps[] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	{ .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; GENLTEST_MC_GRP_NAME },
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally the struct describing our family, where we include everything so far:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Generic Netlink family *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; genl_family genl_fam &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;name	  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; GENLTEST_GENL_NAME,
&lt;&#x2F;span&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;version  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; GENLTEST_GENL_VERSION,
&lt;&#x2F;span&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;maxattr  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; GENLTEST_A_MAX,
&lt;&#x2F;span&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ops	  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; genl_ops,
&lt;&#x2F;span&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;n_ops	  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ARRAY_SIZE&lt;&#x2F;span&gt;&lt;span&gt;(genl_ops),
&lt;&#x2F;span&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;mcgrps	  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; genl_mcgrps,
&lt;&#x2F;span&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;n_mcgrps &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ARRAY_SIZE&lt;&#x2F;span&gt;&lt;span&gt;(genl_mcgrps),
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On initialization of our module, we need to register our family with Generic
Netlink. For that we just need to pass it our &lt;code&gt;genl_family&lt;&#x2F;code&gt; structure:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span&gt;ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genl_register_family&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;genl_fam);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;unlikely&lt;&#x2F;span&gt;&lt;span&gt;(ret)) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_crit&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to register generic netlink family&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; etc...
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And similarly, on module exit we need to unregister it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;unlikely&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genl_unregister_family&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;genl_fam))) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to unregister generic netlink family&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you may have noticed, we set our doit callback for our &quot;echo&quot; command to a
&lt;code&gt;echo_doit&lt;&#x2F;code&gt; function. Here&#x27;s what it looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Handler for GENLTEST_CMD_ECHO messages received *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;echo_doit&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; sk_buff &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;skb&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; genl_info &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;info&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;		ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;void	       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;hdr;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; sk_buff &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;msg;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Check if the attribute is present and print it *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(info-&amp;gt;attrs[GENLTEST_A_MSG]) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;char &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;str &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nla_data&lt;&#x2F;span&gt;&lt;span&gt;(info-&amp;gt;attrs[GENLTEST_A_MSG]);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_info&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;message received: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, str);
&lt;&#x2F;span&gt;&lt;span&gt;	} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_info&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;empty message received&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Allocate a new buffer for the reply *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	msg &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_new&lt;&#x2F;span&gt;&lt;span&gt;(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;msg) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to allocate message buffer&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span&gt;ENOMEM;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Put the Generic Netlink header *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	hdr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_put&lt;&#x2F;span&gt;&lt;span&gt;(msg, info-&amp;gt;snd_portid, info-&amp;gt;snd_seq, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;genl_fam, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;			  GENLTEST_CMD_ECHO);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;hdr) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to create genetlink header&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_free&lt;&#x2F;span&gt;&lt;span&gt;(msg);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span&gt;EMSGSIZE;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* And the message *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;((ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nla_put_string&lt;&#x2F;span&gt;&lt;span&gt;(msg, GENLTEST_A_MSG,
&lt;&#x2F;span&gt;&lt;span&gt;				  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Hello from Kernel Space, Netlink!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to create message string&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_cancel&lt;&#x2F;span&gt;&lt;span&gt;(msg, hdr);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_free&lt;&#x2F;span&gt;&lt;span&gt;(msg);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; out;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Finalize the message and send it *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_end&lt;&#x2F;span&gt;&lt;span&gt;(msg, hdr);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_reply&lt;&#x2F;span&gt;&lt;span&gt;(msg, info);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_info&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;reply sent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;out:
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; ret;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In summary, when handling a do command we follow these steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Get the data from the incoming message from the &lt;code&gt;genl_info&lt;&#x2F;code&gt; structure.&lt;&#x2F;li&gt;
&lt;li&gt;Allocate a new message buffer for the reply.&lt;&#x2F;li&gt;
&lt;li&gt;Put the Generic Netlink header in the message buffer; notice that we use the
same port id and sequence number as in the incoming message since this is a
reply.&lt;&#x2F;li&gt;
&lt;li&gt;Put all our payload attributes.&lt;&#x2F;li&gt;
&lt;li&gt;Send the reply.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Now let&#x27;s take a look at how to send multicast notifications. I&#x27;ve used sysfs to
make this example a little bit more fun; I&#x27;ve created a kobj called &lt;code&gt;genltest&lt;&#x2F;code&gt;
which contains a &lt;code&gt;ping&lt;&#x2F;code&gt; attribute from which we will echo what is written to it.
For brevity I&#x27;ll elide the sysfs code from the article and just add the function
that forms and sends the message here:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Multicast ping message to our genl multicast group *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;echo_ping&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;char &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;buf&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;size_t &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;cnt&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;		ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;void	       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;hdr;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Allocate message buffer *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; sk_buff &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;skb &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_new&lt;&#x2F;span&gt;&lt;span&gt;(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;unlikely&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;skb)) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to allocate memory for genl message&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span&gt;ENOMEM;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Put the Generic Netlink header *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	hdr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_put&lt;&#x2F;span&gt;&lt;span&gt;(skb, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;genl_fam, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, GENLTEST_CMD_ECHO);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;unlikely&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;hdr)) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to allocate memory for genl header&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_free&lt;&#x2F;span&gt;&lt;span&gt;(skb);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span&gt;ENOMEM;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* And the message *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;((ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nla_put_string&lt;&#x2F;span&gt;&lt;span&gt;(skb, GENLTEST_A_MSG, buf))) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;unable to create message string&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_cancel&lt;&#x2F;span&gt;&lt;span&gt;(skb, hdr);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_free&lt;&#x2F;span&gt;&lt;span&gt;(skb);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; ret;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Finalize the message *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_end&lt;&#x2F;span&gt;&lt;span&gt;(skb, hdr);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Send it over multicast to the 0-th mc group in our array. *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_multicast&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;genl_fam, skb, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, GFP_KERNEL);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;== -&lt;&#x2F;span&gt;&lt;span&gt;ESRCH) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_warn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;multicast message sent, but nobody was listening...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else if &lt;&#x2F;span&gt;&lt;span&gt;(ret) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to send multicast genl message&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pr_info&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;multicast message sent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; ret;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The process is very similar to the do operation, except that we are not
responding to a request but sending an asynchronous message. Because of that we
are setting the sequence number to 0, since it is not of consequence here, and
the port id to 0, the kernel port&#x2F;PID. We also sent the message via the
&lt;code&gt;genlmsg_multicast()&lt;&#x2F;code&gt; function.&lt;&#x2F;p&gt;
&lt;p&gt;This is all for the kernel side of things for this tutorial. Now let&#x27;s take a
look at the user side of things.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;user-land&quot;&gt;User land&lt;&#x2F;h3&gt;
&lt;p&gt;Netlink is a socket family and so it&#x27;s possible to communicate over Netlink by
just opening a socket and send and receiving messages over it, something like
this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; fd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;socket&lt;&#x2F;span&gt;&lt;span&gt;(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Format request message... *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* ... *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Send it *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(fd, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;req, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt;(req), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Receive response *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;recv&lt;&#x2F;span&gt;&lt;span&gt;(fd, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;resp, BUF_SIZE, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Do something with response... *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* ... *&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That said, it&#x27;s better to make use of the libnl&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; library or similar since
they provide a better way to interface with Generic Netlink that is less prone
to errors and already contains all the boilerplate that you would need to write
anyway. This library is precisely the one that I&#x27;ll be using in this example.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;ll need to include some headers from the libnl library to get started:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;netlink&#x2F;socket.h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;netlink&#x2F;netlink.h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;netlink&#x2F;genl&#x2F;ctrl.h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;netlink&#x2F;genl&#x2F;genl.h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;netlink&#x2F;genl&#x2F;family.h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As well as our shared header with the enumerations and defines from the kernel
module:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;..&#x2F;ks&#x2F;genltest.h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;ve also made a little helper macro for printing errors:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;fprintf&lt;&#x2F;span&gt;&lt;span&gt;(stderr, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;error: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; __VA_ARGS__)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As I mentioned in the introduction, it&#x27;s easier to use different sockets for
unicast and multicast messages, so that&#x27;s what I&#x27;m going to be doing here,
opening two different sockets to connect to Generic Netlink:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Allocate netlink socket and connect to generic netlink *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;conn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nl_sock &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;sk&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;sk &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_socket_alloc&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;sk) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span&gt;ENOMEM;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genl_connect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;sk);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nl_sock &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;ucsk, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;mcsk;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * We use one socket to receive asynchronous &amp;quot;notifications&amp;quot; over
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * multicast group, and another for ops. We do this so that we don&amp;#39;t mix
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * up responses from ops with notifications to make handling easier.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;((ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;conn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;ucsk)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;|| &lt;&#x2F;span&gt;&lt;span&gt;(ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;conn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;mcsk))) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to connect to generic netlink&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; out;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we need to resolve the ID of the Generic Netlink family that we want to
connect to:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Resolve the genl family. One family for both unicast and multicast. *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; fam &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genl_ctrl_resolve&lt;&#x2F;span&gt;&lt;span&gt;(ucsk, GENLTEST_GENL_NAME);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(fam &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to resolve generic netlink family: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;	      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;strerror&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;fam));
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; out;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A (Generic) Netlink socket is not associated with a family, we are going to need
the family ID when sending the message a little bit later.&lt;&#x2F;p&gt;
&lt;p&gt;The libnl library can do sequence checking for us, but we don&#x27;t need it for
multicast messages, so we disable it for our multicast socket:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_socket_disable_seq_check&lt;&#x2F;span&gt;&lt;span&gt;(mcsk);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also need to resolve the multicast group name. In this case we are going to
be using the resolved ID right away to subscribe to the group and start
receiving the notifications:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Resolve the multicast group. *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; mcgrp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genl_ctrl_resolve_grp&lt;&#x2F;span&gt;&lt;span&gt;(mcsk, GENLTEST_GENL_NAME,
&lt;&#x2F;span&gt;&lt;span&gt;				  GENLTEST_MC_GRP_NAME);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(mcgrp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to resolve generic netlink multicast group: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;	      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;strerror&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;mcgrp));
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; out;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Join the multicast group. *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;((ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_socket_add_membership&lt;&#x2F;span&gt;&lt;span&gt;(mcsk, mcgrp) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to join multicast group: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;strerror&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;ret));
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; out;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We need to modify the default callback so that we can handle the incoming
messages:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Modify the callback for replies to handle all received messages *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static inline &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;set_cb&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nl_sock &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;sk&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_socket_modify_cb&lt;&#x2F;span&gt;&lt;span&gt;(sk, NL_CB_VALID, NL_CB_CUSTOM,
&lt;&#x2F;span&gt;&lt;span&gt;				    echo_reply_handler, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;((ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;set_cb&lt;&#x2F;span&gt;&lt;span&gt;(ucsk)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;|| &lt;&#x2F;span&gt;&lt;span&gt;(ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;set_cb&lt;&#x2F;span&gt;&lt;span&gt;(mcsk))) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to set callback: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;strerror&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;ret));
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;goto&lt;&#x2F;span&gt;&lt;span&gt; out;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, we set the handler function to the same for both sockets, since
we will be basically receiving the same message format for both the do request
and the notifications. Our handler looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * Handler for all received messages from our Generic Netlink family, both
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * unicast and multicast.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;echo_reply_handler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nl_msg &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;msg&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;arg&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;		   err	   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; genlmsghdr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;genlhdr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_hdr&lt;&#x2F;span&gt;&lt;span&gt;(msg));
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nlattr	  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;tb[GENLTEST_A_MAX &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Parse the attributes *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	err &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nla_parse&lt;&#x2F;span&gt;&lt;span&gt;(tb, GENLTEST_A_MAX, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_attrdata&lt;&#x2F;span&gt;&lt;span&gt;(genlhdr, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;			&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_attrlen&lt;&#x2F;span&gt;&lt;span&gt;(genlhdr, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(err) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;unable to parse message: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;strerror&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;err));
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; NL_SKIP;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Check that there&amp;#39;s actually a payload *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;tb[GENLTEST_A_MSG]) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;msg attribute missing from message&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; NL_SKIP;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Print it! *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;message received: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nla_get_string&lt;&#x2F;span&gt;&lt;span&gt;(tb[GENLTEST_A_MSG]));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; NL_OK;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nothing that fancy going on here, much of it is very similar to what we were
doing on the kernel side of things. The main difference is that the message was
already parsed for us by the kernel API, while here we have the option to walk
the attributes manually or parse them all onto an array with the help of library
function.&lt;&#x2F;p&gt;
&lt;p&gt;Next we want to send a message to kernel space:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Send (unicast) GENLTEST_CMD_ECHO request message *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;send_echo_msg&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nl_sock &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;sk&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;fam&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;	       err &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nl_msg &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;msg &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_alloc&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;msg) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span&gt;ENOMEM;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Put the genl header inside message buffer *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;hdr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;genlmsg_put&lt;&#x2F;span&gt;&lt;span&gt;(msg, NL_AUTO_PORT, NL_AUTO_SEQ, fam, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;				GENLTEST_CMD_ECHO, GENLTEST_GENL_VERSION);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;hdr) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span&gt;EMSGSIZE;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Put the string inside the message. *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	err &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nla_put_string&lt;&#x2F;span&gt;&lt;span&gt;(msg, GENLTEST_A_MSG,
&lt;&#x2F;span&gt;&lt;span&gt;			     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Hello from User Space, Netlink!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(err &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return -&lt;&#x2F;span&gt;&lt;span&gt;err;
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;message sent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Send the message. *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;	err &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_send_auto&lt;&#x2F;span&gt;&lt;span&gt;(sk, msg);
&lt;&#x2F;span&gt;&lt;span&gt;	err &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; err &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;? &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; err;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nlmsg_free&lt;&#x2F;span&gt;&lt;span&gt;(msg);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; err;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Send unicast message and listen for response. *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;((ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;send_echo_msg&lt;&#x2F;span&gt;&lt;span&gt;(ucsk, fam))) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;prerr&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;failed to send message: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;strerror&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;ret));
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Also not that different from the kernel API. Now we listen once for the response
to our command and indefinitely for incoming notifications:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;listening for messages&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_recvmsgs_default&lt;&#x2F;span&gt;&lt;span&gt;(ucsk);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Listen for &amp;quot;notifications&amp;quot;. *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_recvmsgs_default&lt;&#x2F;span&gt;&lt;span&gt;(mcsk);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As good hygiene, let&#x27;s close the connection and socket before exiting our
program:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;* Disconnect and release socket *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;disconn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; nl_sock &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;sk&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_close&lt;&#x2F;span&gt;&lt;span&gt;(sk);
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nl_socket_free&lt;&#x2F;span&gt;&lt;span&gt;(sk);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; * ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt; *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;disconn&lt;&#x2F;span&gt;&lt;span&gt;(ucsk);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;disconn&lt;&#x2F;span&gt;&lt;span&gt;(mcsk);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s about it!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The old ways of interacting with the kernel and its different subsystems through
such interfaces as sysfs and especially ioctl had many downsides and lacked some
very needed features such as asynchronous operations and a properly structured
format.&lt;&#x2F;p&gt;
&lt;p&gt;Netlink, and its extended form, Generic Netlink, provide a very flexible way of
communicating with the kernel, solving many of the downsides and problems of the
interfaces of old. It&#x27;s certainly not a perfect solution (not very Unixy for
instance), but it&#x27;s certainly the best way we have to communicate with the
kernel for things more complicated than setting simple parameters.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;post-scriptum&quot;&gt;Post scriptum&lt;&#x2F;h2&gt;
&lt;p&gt;At the moment when I started learning to use Generic Netlink, the 6.0 kernel
wasn&#x27;t yet stable, hence the excellent kernel docs Netlink intro&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; wasn&#x27;t yet
in the &quot;latest&quot; section, but rather in the &quot;next&quot; section. Since I was looking
inside the then &quot;latest&quot; (v5.19) docs, I didn&#x27;t notice it until I started
writing my own article.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not sure if I had started writing this article had I come across the new
kernel docs page, but in the end I think it was worth it since this one is a
good complement to the official docs if you want to get your hands dirty
straight away, especially considering that it provides a practical example.&lt;&#x2F;p&gt;
&lt;p&gt;Do give a read to the kernel docs page! It covers some things that might not be
covered here.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Original site with documentation &lt;a href=&quot;https:&#x2F;&#x2F;www.infradead.org&#x2F;~tgr&#x2F;libnl&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.infradead.org&#x2F;~tgr&#x2F;libnl&#x2F;&lt;&#x2F;a&gt;,
up-to-date repository: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thom311&#x2F;libnl&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;thom311&#x2F;libnl&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Very good introductory Netlink article, from the kernel docs themselves:
&lt;a href=&quot;https:&#x2F;&#x2F;kernel.org&#x2F;doc&#x2F;html&#x2F;latest&#x2F;userspace-api&#x2F;netlink&#x2F;intro.html&quot;&gt;https:&#x2F;&#x2F;kernel.org&#x2F;doc&#x2F;html&#x2F;latest&#x2F;userspace-api&#x2F;netlink&#x2F;intro.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Overcomplicated</title>
		<published>2023-01-31T22:18:53+00:00</published>
		<updated>2023-01-31T22:18:53+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/overcomplicated/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/overcomplicated/</id>
		<content type="html">&lt;p&gt;We take it as a fact that life is simpler for man these days than it was even a
couple hundred years ago, let alone a thousand years ago. We hear it all the
time. If we take a closer look to even what has been happening in the last 20 to
30 years, it might turn out that life might not be getting simpler anymore.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;If we are talking about surviving, then yes, most certainly it has become quite
simple for people to live to see another day and to avoid many of the natural
causes of death, even those as simple as starvation and disease. That is, if we
talk about the developed world from the point of view from which I&#x27;ll be
writing, since even in most of the not so developed parts of the world the
advances of the developed nations have been seeping through.&lt;&#x2F;p&gt;
&lt;p&gt;Mostly of course, life expectancy wasn&#x27;t that great before not because people
didn&#x27;t live until old age, but rather because not many children survived into
adulthood, or even birth, for that matter. The point, however, is not that, but
the fact that for one to be able to just survive and live to see another day —
to not die of starvation or disease, or be killed by wild animals — is pretty
easy nowadays.&lt;&#x2F;p&gt;
&lt;p&gt;That said, surviving for a man isn&#x27;t really the goal, but rather the means. Man
is more complex than a simple animal, he seeks to find meaning in life,
accomplish great achievements, produce great things and maybe leave something to
be remembered for, at least by the people closest to him.&lt;&#x2F;p&gt;
&lt;p&gt;So for man to be happy he needs to constantly go through some effort to achieve
something worth of that effort. It is by this process that men acquire the
feeling of accomplishment. What changes for each person is what is worth
achieving. But if something doesn&#x27;t require much effort then one doesn&#x27;t feel as
if they&#x27;ve really achieved it.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, if something is difficult but is deemed as not being worth
one&#x27;s attention or unnecessary, we try to avoid it. If it cannot be avoided it
causes one to feel annoyed, stressed, etc.&lt;&#x2F;p&gt;
&lt;p&gt;There are, of course, some factors that cannot be avoided, that are part of the
physical limitations of life itself. They can be quite unpleasant, but by
consciously or unconsciously being aware that they absolutely can&#x27;t be helped
one doesn&#x27;t feel as bothered by them as by those things that we know that are
artificially made difficult.&lt;&#x2F;p&gt;
&lt;p&gt;Now, as I mentioned earlier, covering one&#x27;s basic needs has really become so
much simpler that even though most of a man&#x27;s life in the past was devoted to
them, nowadays has been relegated to basically just a small fraction of a
person&#x27;s day. This is of course great, since it allows man to pursue greater
achievements that he may set his sight on. It also allows for debauchery and
degeneracy among those unfortunate people that have bought into the thought that
happiness and freedom mean indulging in hedonistic activities without
restrictions, but that is a topic for another day.&lt;&#x2F;p&gt;
&lt;p&gt;Even though those basic tasks have been significantly easier, there are some
other aspects of life that are becoming more complex than necessary.&lt;&#x2F;p&gt;
&lt;p&gt;Life shouldn&#x27;t be simple. There should be hardships in life, but, as I
mentioned, they should be the kinds of hardships through which we accomplish
something great. Yet modern life is becoming more complex and difficult in
precisely the wrong ways.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tis-actually-a-rant&quot;&gt;&#x27;tis actually a rant&lt;&#x2F;h2&gt;
&lt;p&gt;It has been a really long introduction for a very simple rant, but I wanted to
give some context first.&lt;&#x2F;p&gt;
&lt;p&gt;There are some things that used to be much simpler that are now becoming more
complex and annoying without any benefit whatsoever.&lt;&#x2F;p&gt;
&lt;p&gt;Probably not all of the examples that I&#x27;ll list are actually that way in other
parts of the world (I live in Russia), but I get the feeling from what I see
online and talking to other people that it is not much different in most of the
developed (so-called developing countries included) world, and even though some
examples might be exclusively local phenomena most probably there are different
examples from other parts of the world that are at least in similar in nature.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also not an exhaustive list, but you get the idea.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Electronic or electric crap where it doesn&#x27;t make any sense. An example of
this is the electric seats that now come as standard in some cars. It&#x27;s much
faster and easier to adjust it with ye olde mechanical levers, not to mention
that they are more durable than their electric counterparts.&lt;&#x2F;li&gt;
&lt;li&gt;It&#x27;s become nearly impossible to live without a cellphone. You need it for
your bank, many online services, and even some offline ones. Online services
shove it unto you in the form of totally insecure yet terribly cumbersome SMS
2FA; and now you can&#x27;t even properly dine at some restaurants because to read
the menu you now have to scan a goddamned QR code.&lt;&#x2F;li&gt;
&lt;li&gt;IoT in general, but especially in consumer and home appliances. There are some
appliances which are still easy to find in their &quot;dumb&quot; (or rather
non-retarded) versions, but there are others such as TVs which are almost
impossible to find without &quot;smart&quot; crap. I don&#x27;t want my fridge to connect to
the internet, I just want it to keep my food cool so that it doesn&#x27;t spoil. In
fact, I don&#x27;t want anything other than my computer(s), my phone, my home
server and my router to connect to the internet. Now that I think about it, I
might even want for my phone to not be connected to the internet.&lt;&#x2F;li&gt;
&lt;li&gt;(Online) accounts for everything. This has become so bad, that I have to split
it into subpoints.
&lt;ul&gt;
&lt;li&gt;Computers - fortunately, when it comes to general computing devices I don&#x27;t
use proprietary systems that impose this crap unto me. It still baffles me
the way in which using computers has become so much harder for users of such
consumer-oriented proprietary systems such as Windows. You have to have a M$
account for that and for this, the default is now not a local account but
the M$ account when installing Winblows. I haven&#x27;t used Windows in a long
time, but I wouldn&#x27;t be surprised if now you couldn&#x27;t even use the
non-professional version without first signing-into a M$ server.&lt;&#x2F;li&gt;
&lt;li&gt;Appliances - I sometimes play friends in some bars in gaming consoles. I
remember when playing videogames from a console was as simple as putting the
media and powering it on. Now you are constantly pestered to log in, not to
mention that in most cases you also have to install the game or even
&quot;first-day&quot; updates. Here also comes to mind the case with most
&quot;smart&quot;-anything, such as TVs.&lt;&#x2F;li&gt;
&lt;li&gt;Day-to-day life - this cancer of accounts has been seeping and spreading
into day-to-day real life as well, which is even worse. Now if you make the
mistake of actually giving your phone number for one those discount cards
you suddenly find yourself with an account (even though it might not be
obvious at first) and a lot of SMS spam. But worse of all, government
related accounts. It&#x27;s okay when online government services are offered as
an &lt;strong&gt;alternative&lt;&#x2F;strong&gt;, but now there are certain things which can&#x27;t be done at
all without having to register an account in their web services, which are
developed by incompetent government workers that haven&#x27;t heard the word
security or privacy in their lives.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;You can&#x27;t just go into a supermarket and just buy what you need like it used
to be, you are bombarded by discount offers, coupons and the like. Just when
you are about to pay you are asked if you have their discount or loyalty card
and god forbid you don&#x27;t you are asked if you would like to get it. Every
single time.&lt;&#x2F;li&gt;
&lt;li&gt;Advertisements everywhere. There&#x27;s nothing inherently wrong with
advertisements in and of themselves, the problem is that they are now
everywhere. Websites, supermarkets, apps, home appliances, operating systems,
cars, your mail box, your email inbox, etc. they are all filled with
advertisements. It&#x27;s become a circlejerk of everything trying to sell you
something. Want to open the car sharing app to rent a car? How about some
discount for coffee? Maybe if I wanted to drink some coffee I would have gone
to the store or café to buy some.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These are just some of the examples of the way in which so-called &quot;progress&quot; is
actually making life worse instead of improving it.&lt;&#x2F;p&gt;
&lt;p&gt;We are getting better at certain things, like more efficient engines and more
powerful computers, but the end experience in most products and services is
getting worse.&lt;&#x2F;p&gt;
&lt;p&gt;The point of technology is to be used as a tool to give more freedom to people
and make life simpler. Instead of that, people are becoming less free by being
hyper-dependent on technology and complicating life all around.&lt;&#x2F;p&gt;
&lt;p&gt;The worst part of all of this is that there is no reason why things should be
made this way. Not even profit, since even though that seems to be the goal most
of the time, it doesn&#x27;t really contribute to making life better for their
customers so that they actually spend money on things they actually need or
want. It seems to be that the people that were inventing and making things some
30 years ago were actually interested in improving the experience of their
users, be it a simple TV or a car. Now it seems that it&#x27;s just a matter of who
has the shiniest new features or whatever is being hyped now.&lt;&#x2F;p&gt;
&lt;p&gt;I do have to wonder what all the developers and engineers that design such
systems are thinking. Maybe they are told by their management that it is what
needs to be done, but certainly they must have some agency to know better and do
better. Not doing anything is better than being complicit in building the
nightmare that is being built nowadays.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t really think that the people that are complicit in this really think
that this makes their lives better. Even if it brings them money, now that money
can&#x27;t be spent on anything that gives you exactly what you need.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Liberating my X200</title>
		<published>2022-10-23T23:56:42+00:00</published>
		<updated>2022-10-23T23:56:42+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/x200-libreboot/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/x200-libreboot/</id>
		<content type="html">&lt;p&gt;I had wanted to libreboot my trusty old Thinkpad X200 for quite sometime. Only
recently did I get around to librebooting mine. Even though the information on
how to do it is out there and quite good, some of it is spread throughout the
internet and didn&#x27;t all completely apply to my particular case, hence I decided
to write this post on how I went about flashing Libreboot on my X200.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;I had been wanting to flash Libreboot on my X200 ever since I got it, but only
recently did I get around actually doing it. The process isn&#x27;t hard at all, you
don&#x27;t need any special skills besides knowing how to use the Linux command line
and not being afraid to open your laptop and connecting some wires to it.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s many reasons to want to install Libreboot or Coreboot, some which are
faster boot times, custom payloads, and of course, muh freedumbs. I was mainly
looking for faster boot times and having an almost completely free and open
source laptop without backdoors, i.e. Intel ME&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For this I used a CH341A programmer. Yes, the official Libreboot site&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; warns
against using it, but really it just because of a batch of faulty boards that
deliver 5V instead of 3.3V on the 3.3V pin. That said, if you have a multimeter
lying around it quite easy to make sure that you have a proper CH341A with 3.3V
DC instead of 5V. After plugging my multimeter I found that mine was fine and so
I proceeded to use to flash my laptop.&lt;&#x2F;p&gt;
&lt;p&gt;Most Thinkpads out there have 16 pin SPI chip, and that&#x27;s why most information
out there is about them, but mine had an 8 pin. In my case that was better for
me, since the CH341A I bought came with a SOIC8 clip, so I didn&#x27;t have to buy
a separate clip. I did end up desoldering the cables that came attached to the
clip since I wanted to use jumper female-female cables to connect the clip to
the CH341A.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;libreboot-01.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;libreboot-01.jpg&quot; alt=&quot;Unsoldered SOIC8 clip&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Unsoldered SOIC8 clip next to the CH341A with jumper cables already connected to
the board.&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;After unsoldering the clip, I went ahead and opened my laptop. It&#x27;s only
necessary to remove the keyboard and palmrest to get access to the chip.
Removing the keyboard and palmrest assembly is really easy. The only thing that
you need to do is unscrew 8 phillip-head screws which are marked with the
palmrest and the keyboard icons, the push the keyboard towards the screen pull
it up, disconnect it and next lift off the palmrest. You might need to also
disconnect the fingerprint reader if you have one, mine doesn&#x27;t so I didn&#x27;t have
to. Also, don&#x27;t forget to remove the laptop battery and disconnect the CMOS
battery.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;libreboot-02.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;libreboot-02.jpg&quot; alt=&quot;Removing keyboard and palmrest&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Removing the keyboard and palmrest.&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;After getting the keyboard and palmrest out of the way, there was the chip. All
of those chips have a dot indicating pin 1. It&#x27;s important to locate pin 1 in
order to know how to properly connect the pins to the flashing board. The
scheme is as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;x200-soic8.svg&quot; alt=&quot;Thinkpad X200 SOIC8 scheme&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Wire all of the pins on the chip to the following pins on the CH341A:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;CS&lt;&#x2F;li&gt;
&lt;li&gt;MISO&#x2F;MIOS&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;unused&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;GND&lt;&#x2F;li&gt;
&lt;li&gt;MOSI&lt;&#x2F;li&gt;
&lt;li&gt;CLK&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;unused&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;3.3V&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;After wiring up properly the clip to the CH341A, I proceeded to secure the clip
to the chip by making sure that pin 1 was correctly wired to CS on the CH341A.
Then, after making sure that the clip was properly and securely in place, I
proceeded to connect the CH341A to the host computer from which I would be
flashing. &lt;strong&gt;It&#x27;s very important to first connect the clip and then the board to
the host, otherwise you risk frying your chip and bricking your laptop!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;libreboot-03.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;libreboot-03.jpg&quot; alt=&quot;CH341A connected to the chip&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;CH341A connected to the chip and host computer.&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;For reading and flashing SPI chips, a program called flashrom is needed, which
is available in most distributions&#x27; repos.&lt;&#x2F;p&gt;
&lt;p&gt;After I checked dmesg to see that the CH341A properly recognized by the host, I
went ahead and proceeded to dump the original firmware. I did this twice to run
a diff on both dumps and make sure that I was getting correct readings before
actually flashing the Libreboot image:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# flashrom -p ch341a_spi -r bak1.rom
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;# flashrom -p ch341a_spi -r bak2.rom
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;# diff bak1.rom bak2.rom
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I got an empty output from diff, which means that the two reads were
identically, and so I could continue with more confidence that I wouldn&#x27;t brick
my laptop. Also, from the output, I could gather that my chip was a 4mb one, so
the image that I downloaded was the 20220710 4mb release for the X200. All
Libreboot images can be downloaded from here:
&lt;a href=&quot;https:&#x2F;&#x2F;libreboot.org&#x2F;download.html&quot;&gt;https:&#x2F;&#x2F;libreboot.org&#x2F;download.html&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I chose to install the one with grub as first payload and SeaBios as secondary
since I only use Linux. After choosing and downloading the image I proceeded to
flash it:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# flashrom -p ch341a_spi -w grub_x200_4mb_libgfxinit_corebootfb_usqwerty.rom
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After a couple of minutes of flashing it was done. I was now able to fully enjoy
muh freedumbs. I assembled back the computer and booted it up and there it was,
the libreboot grub menu greeting me.&lt;&#x2F;p&gt;
&lt;p&gt;Everything was fine until the computer froze, I rebooted it and was greeted by
some weird noise on the screen and nothing else. I fiddled around, dumped the
chip to check it was correctly flashed (it was), tried different images, until
it dawned on me that I had two different RAM sticks on my X200, a 4GB one and a
2GB one. After removing the 2GB one everything went back to normal.&lt;&#x2F;p&gt;
&lt;p&gt;Libreboot&#x2F;Coreboot does indeed boot much faster than the native firmware. It
even wakes up instantaneously from sleep, whereas with the native firmware it
would take 1-2s seconds to do so. I also noticed slightly better graphics
performance, which could be attributed to the bigger amount of RAM that is
dedicated to iGPU with Libreboot compared to the native firmware.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;libreboot-04.jpg&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;x200-libreboot&#x2F;libreboot-04.jpg&quot; alt=&quot;X200 Libreboot grub menu&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;Muh freedumbs!&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;That&#x27;s it, it really is that easy. After flashing Libreboot it is possible to
flash the SPI chip using software only without having to use an external
flasher. It&#x27;s as simple as using the flashrom program, except that you use &lt;code&gt;-p internal&lt;&#x2F;code&gt; to let know flashrom that you will be flashing the chip internally.&lt;&#x2F;p&gt;
&lt;p&gt;If you are interested in making any further modifications to your Libreboot
image, it&#x27;s best to read the official Libreboot and possibly Coreboot resources.
If, for example, you want to change GRUB&#x27;s background just as I did, you can
read more about it here: &lt;a href=&quot;https:&#x2F;&#x2F;libreboot.org&#x2F;docs&#x2F;gnulinux&#x2F;grub_cbfs.html&quot;&gt;https:&#x2F;&#x2F;libreboot.org&#x2F;docs&#x2F;gnulinux&#x2F;grub_cbfs.html&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;The Intel Management Engine is a secondary processor installed on all
Intel chips from circa 2007 onwards. It runs its own OS and environment and
has full control over the machine, furthermore it can&#x27;t be officially disabled
by the user, and requires measures such as flashing custom firmware or even
soldering&#x2F;desoldering certain components in order for it to be completely
neutered. It&#x27;s a huge security risk, but unfortunately one can&#x27;t be easily
mitigated and continues to be deployed like a virus in all modern x86
machines. Yes, AMD also has its own version of the ME called the PSP or
Platform Security Processor. Another reason why closed proprietary systems are
a bad thing for privacy, security and freedom.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;libreboot.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;libreboot.org&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>It&#x27;s time to use crypto</title>
		<published>2022-04-15T20:54:32+00:00</published>
		<updated>2022-04-19T23:06:37+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/time-to-use-crypto/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/time-to-use-crypto/</id>
		<content type="html">&lt;p&gt;Cryptocurrencies have been around for well over a decade. Everybody who&#x27;s ever
used the internet has at least some basic understanding of what a cryptocurrency
is, yet most people seem to miss the point of cryptocurrencies. Nevertheless,
recent events have shown us how important this technology actually is and why it
is better than the alternative.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Long gone are the days when simply exchanging one product or service for another
suffices. We have a better way of exchanging value through our monetary system.
The classical monetary system is also not enough anymore. Gone are the days of
the gold standard, and here be the days of instantaneous transactions across the
whole world using electronic means to transfer money.&lt;&#x2F;p&gt;
&lt;p&gt;However, with all those benefits have come a lot of drawbacks that have reduced
our freedoms and intruded in our privacy. If you want to trade electronically
across countries or even inside the same city, you have to go through a dozen of
intermediaries each of whom gets a piece of the transaction, each of whom has
their own rules and each of whom can track what each person buys and sells at
any moment.&lt;&#x2F;p&gt;
&lt;p&gt;Basically, we&#x27;ve allowed ourselves to take part in an Orwellian financial system
that has the say on how, when and with whom we are allowed to trade. The worst
part is that we all are taking part in this voluntarily.&lt;&#x2F;p&gt;
&lt;p&gt;Many people might dismiss the arguments against such centralized control of the
finances as being paranoid, but there are already great examples of why such
centralized control is bad for people&#x27;s ability to trade freely.&lt;&#x2F;p&gt;
&lt;p&gt;Starting from people with opinions that are not very popular among those in
charge to now, canceling an entire country because the government of said
country did something that the powers that be didn&#x27;t like. It&#x27;s nothing new that
we are limited by the rules of of those who are in charge of the system. After
all it&#x27;s their system and they set the rules. That said it&#x27;s not like there are
no alternatives.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s where cryptocurrencies come in. Whereas traditionally financial systems
have relied on a central authority to set and apply the rules, to mint or print
money basically reducing the wealth of the people that hold said currency at
their mercy, cryptocurrencies allow no one person to control the system.&lt;&#x2F;p&gt;
&lt;p&gt;The premise of cryptocurrency is that no one person controls the system. There
are a set of rules by which all of the parties of the game agree to play, and
each participant controls make sure each other play according to them. If there
is some discrepancy with the rules or some manipulation is seen by the rest of
the participants they won&#x27;t allow such behavior to go on and will simply refuse
the malicious actions to take place.&lt;&#x2F;p&gt;
&lt;p&gt;Basically a cryptocurrency is a network in which anybody can take part, giving
some computer resources in order for the network to work by generating blocks
that contain the transactions and possibly some new unit of cryptocurrency that
is mined. No one party in the network can change the rules. The system is made
in such a way that mathematically no one person can go against the rules (e.g.
double-spending currency) without said person or party owning more than 50% of
the network&#x27;s capacity, which, at least for Bitcoin and most major currencies,
is basically impossible now.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Not all cryptocurrencies are equal, though. Bitcoin is the most popular and the
most valuable crypto out there on the market on the merits of being the first
such system. Back when it was announced and launched by the mysterious Satoshi
Nakamoto it was a revolutionary system. It still is, but it&#x27;s not without it&#x27;s
flaws.&lt;&#x2F;p&gt;
&lt;p&gt;The biggest flaw that I see with Bitcoin is its lack of privacy. I&#x27;m actually
surprised that more governments are not on board with Bitcoin&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, taking into
account how easy it is to track transactions. And it&#x27;s not like it is a bug of
the system or something, it&#x27;s more of a feature actually. In order for the
original concept of the blockchain to work, a public ledger was needed.&lt;&#x2F;p&gt;
&lt;p&gt;Bitcoin also has many other problems such as very poor performance, and its
proof-of-work algorithm being very prone to centralization, or at least making
it harder for smaller players to take part in the system due to how easy it is
to make ASICs for it.&lt;&#x2F;p&gt;
&lt;p&gt;With that said, the biggest advantage of cryptocurrencies still holds for
Bitcoin. It is a &lt;strong&gt;decentralized&lt;&#x2F;strong&gt; currency. No one person, corporation or
government controls it. You can create as many addresses (think of a bank
account) as you want and all it takes is a couple of clicks. No need to enter
into any contracts or give your ID and private information to some bank.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately the biggest problem with Bitcoin, privacy, is fixed in other
cryptocurrencies, namely Monero&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Monero, in my humble opinion, is the one
cryptocurrency which I think offers the most advantages with the less
disadvantages. It&#x27;s not only completely decentralized as Bitcoin, but it also
offers full privacy by default. Nobody, except for the sending and the receiving
parties, knows how much is being paid, and who is paying whom.&lt;&#x2F;p&gt;
&lt;p&gt;Apart from that I have also found Monero much simpler to use. It is easier to
take part in mining, due to their proof-of-work algorithm, transactions are
faster and commissions are lower. I do think that it is the cryptocurrency to
rule them all.&lt;&#x2F;p&gt;
&lt;p&gt;I had already started using crypto, specifically Monero, since some time ago,
and was interested in the technology since I found about it in the early 2010&#x27;s.
However, I was never really an active user. For me, that has changed now.&lt;&#x2F;p&gt;
&lt;p&gt;On the 24th of February the Russian government decided to actually do something
about the conflict that was already happening since 8 years ago. Of course, the
United States didn&#x27;t like it that somebody else had some agency over their
interests proceeding to have a hissy fit and basically taking cancel culture to
a whole new level by what amounts to trying to cancel the entirety of Russia.&lt;&#x2F;p&gt;
&lt;p&gt;The irony of the situation is intense, not only are those sanctions affecting
mostly people who have nothing to do with the conflict, they are also affecting
the people who they are supposedly defending with these sanctions. Believe it or
not, many Russian people have relatives in Ukraine.&lt;&#x2F;p&gt;
&lt;p&gt;And of course the hypocrisy is through the roof. I&#x27;m not taking about the
American government themselves, of course they would act like they do, might
makes right in our world after all. I&#x27;m talking about all of the other countries
and the corporations that are &quot;supporting Ukraine&quot; by &quot;stopping all work in
Russia&quot;. Nowhere to be seen was their support of the people that the US
&lt;del&gt;glowniggers&lt;&#x2F;del&gt; government invaded or carpet bombed, but anyways, that&#x27;s a
little off topic.&lt;&#x2F;p&gt;
&lt;p&gt;The point being that the ability of the Russian and Ukrainian people to trade
with other people is being crippled right now because of the decisions of some
politicians and businessmen. The Ukraine is of course the most affected right
now, since it has itself become the victim of a proxy war between the US&#x2F;NATO
and Russia. And those of us who live in Russia now cannot properly trade with
people of other countries, or even send money to relatives in other countries.&lt;&#x2F;p&gt;
&lt;p&gt;These problems can be overcome fully only by using a fully decentralized
electronic money system.&lt;&#x2F;p&gt;
&lt;p&gt;I think, and I actually hope, that cryptocurrencies will never replace cold hard
cash. I would prefer, of course, if we traded in non-fiat currencies, but that
is a story for another day. I do think that cryptocurrencies should become the
standard for electronic transactions.&lt;&#x2F;p&gt;
&lt;p&gt;I care not for who is in charge, be it a corporation or a government, neither of
them actually have&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; your or my interests in mind. The only solution to the
problem is something that is not controlled by anybody.&lt;&#x2F;p&gt;
&lt;p&gt;Personally, since the start of this conflict I have started to use more
cryptocurrency, especially as a store of value. Right now inflation, both in
Russia, where I live, and outside of Russia, is really high which means that
fiat currencies are just a loss of money if you hold&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; them. Right now even a
savings account isn&#x27;t actually that worth it. On the other hand, Bitcoin and
Monero are overall deflationary so, even though not as good as precious metals
or real estate, they are a pretty good way to store value and keep some savings.&lt;&#x2F;p&gt;
&lt;p&gt;In short, I want to summarize the reasons why I believe cryptocurrencies are the
way to trade electronically:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;No central authority. Nobody can steal your money (close your account, reposes
your funds, etc). because someone (bank, government, etc.) said so. Only if
someone gets hold of your keys can they steal your money.&lt;&#x2F;li&gt;
&lt;li&gt;There are no terms of service or contracts that you have to sign. Everybody is
free to create an address without any ID or documents, completely anonymously.&lt;&#x2F;li&gt;
&lt;li&gt;Nobody can &quot;print&quot; or create more cryptocurrencies at will, like the Federal
Reserve can with the dollar, or the Central Banks with other currencies, which
leads to the next point:&lt;&#x2F;li&gt;
&lt;li&gt;Crypto is not inflationary; right now most are quite volatile, but overall
they grow in value against fiat currencies.&lt;&#x2F;li&gt;
&lt;li&gt;And, in the case of Monero: your transactions are completely private; there&#x27;s
no government or corporation spying at what you buy or who you send money to.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In this troubling times stay safe and remember, do not trust anybody, with whom
you are not acquainted in real life.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;This is just a very very simple and short overview on how (most)
cryptocurrencies work. If you are interested in learning more, I suggest you
start by reading the bitcoin white paper.
&lt;a href=&quot;https:&#x2F;&#x2F;bitcoin.org&#x2F;en&#x2F;bitcoin-paper&quot;&gt;https:&#x2F;&#x2F;bitcoin.org&#x2F;en&#x2F;bitcoin-paper&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;You know, with how all current governments love to spy on their people and
&lt;del&gt;steal from them&lt;&#x2F;del&gt; tax them as much as possible.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Check out Monero&#x27;s website for more information:
&lt;a href=&quot;https:&#x2F;&#x2F;www.getmonero.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.getmonero.org&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;The government is &lt;em&gt;supposed&lt;&#x2F;em&gt; to have the interests of its people in mind;
the thing is that de facto it has never happened and will never happen.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;Well, they always are, it&#x27;s just higher than usual now.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How I debug programs in Vim</title>
		<published>2022-01-25T19:49:30+00:00</published>
		<updated>2022-01-25T19:49:30+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/debugging-in-vim/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/debugging-in-vim/</id>
		<content type="html">&lt;p&gt;I like to use separate tools for different tasks, and also like it when those
tools integrate with the other tools I use. Unfortunately I haven&#x27;t seen much
information online for possible workflows on debugging programs with Vim. There
is information but it is all spread out. So I decided to write about the
workflow that I&#x27;ve built over the years for writing and debugging programs with
Vim.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Many, or most, IDEs already come with some sort of debugging facility. But
those IDEs are not vim, and more often than not, they also come with a lot of
other features that frankly are not very useful. And no, vimifcation plugins
don&#x27;t count, most of them don&#x27;t cover even half the functionality that vim
offers.&lt;&#x2F;p&gt;
&lt;p&gt;I love using vim (technically neovim, eh, same diff), I really think that it is
the best text editor out there. Hell, I even, unironically, think it might the
program with best UI&#x2F;UX. Sure it is not intuitive at all (&lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;debugging-in-vim&#x2F;#exit-vim&quot;&gt;insert obligatory
exit vim meme&lt;&#x2F;a&gt;), but once you learn the ropes of it, and it doesn&#x27;t
take as long as
they meme it to be, it&#x27;s just bliss. In shot, vim is a lifestyle, not a program.&lt;&#x2F;p&gt;
&lt;p&gt;The problem is that learning to be a power user of vim can take time. And to be
able to efficiently develop programs typing them is not enough. You also need
to navigate around code bases, quickly fix the most basic of errors (such as
typos), reduce repetitive tasks (e.g. autocomplete), and of course, debug and
profile.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately both vim and neovim, for at least some 3–4 years now, offer
facilities to integrate software development and debugging tools with ease.
Since I use neovim, some things that I talk about here might differ a little
bit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;development-tools&quot;&gt;Development tools&lt;&#x2F;h2&gt;
&lt;p&gt;It used to be that each editor&#x2F;IDE needed to have plugins developed for, or even
baked into, them individually. This meant that efforts had to split for every
and each language and editor combination, which meant that not every editor had
support even every popular language.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, Microsoft did a very un-Microsoft thing, and instead of baking in
another completely new implementation of IDE-like development tools for each
language to their VSCode editor, they developed what now is called the Language
Server Protocol&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and with the help of Red Hat et al they open sourced it and
standardized it.&lt;&#x2F;p&gt;
&lt;p&gt;In short, the Language Server Protocol (LSP) is just a JSON RPC protocol for
communications between a server that provides the functions, such as
autocompletion, linting, go-to-definition, etc. and the client which would be
the IDE or editor, which basically displays the results. And one of the editors
that supports LSP is vim. In fact, at least in neovim, the support is built in.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lsp&quot;&gt;LSP&lt;&#x2F;h3&gt;
&lt;p&gt;In order to use LSP in neovim, you need to enable the plugin and configure the
LSP server(s) for your language(s). The good thing is that configuring it is
pretty simple and straightforward, especially since there is a plugin that
already comes with default configurations for a lot of popular languages LSPs.&lt;&#x2F;p&gt;
&lt;p&gt;I use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;junegunn&#x2F;vim-plug&quot;&gt;vim-plug&lt;&#x2F;a&gt; to manage my plugins, so
first I added the official &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;neovim&#x2F;nvim-lspconfig&quot;&gt;lspconfig&lt;&#x2F;a&gt;
plugin:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;vim&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-vim &quot;&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;...
&lt;&#x2F;span&gt;&lt;span&gt;	Plug &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;neovim&#x2F;nvim-lspconfig&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then proceeded to configure it for my needs by adding the configurations for
the LSP servers for C, Go, Rust, Python and Javascript, the languages that I use
the most often:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;vim&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-vim &quot;&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot; LSP
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt; omnifunc=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;v:lua&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;vim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;omnifunc
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;lspconfig&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;clangd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;setup{filetypes = { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;quot;c&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;quot;cpp&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;quot;objc&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;quot;objcpp&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;quot;ch&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; }}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;lspconfig&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;gopls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;setup{}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;lspconfig&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;pylsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;setup{}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;lspconfig&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;rls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;setup{}
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;lspconfig&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;tsserver&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;setup{}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot; LSP keybinds
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;nmap &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;silent&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; gd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;cmd&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua&lt;&#x2F;span&gt;&lt;span&gt; vim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;buf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;definition&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;CR&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;nmap &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;silent&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; gD &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;cmd&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua&lt;&#x2F;span&gt;&lt;span&gt; vim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;buf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;declaration&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;CR&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;nmap &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;silent&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; gK &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;cmd&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua&lt;&#x2F;span&gt;&lt;span&gt; vim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;buf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;hover&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;CR&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;nmap &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;silent&amp;gt; &amp;lt;leader&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;cmd&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua&lt;&#x2F;span&gt;&lt;span&gt; vim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;buf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;rename&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;CR&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;nmap &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;silent&amp;gt; &amp;lt;leader&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;cmd&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;lua&lt;&#x2F;span&gt;&lt;span&gt; vim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;buf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;formatting&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;CR&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot; neovim overrides my omnifunc with whatever ccomplete is, so I use this
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;autocmd &lt;&#x2F;span&gt;&lt;span&gt;FileType c,ch,header,cpp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;setlocal&lt;&#x2F;span&gt;&lt;span&gt; omnifunc=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;v:lua&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;vim&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lsp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;omnifunc
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, in order to use the functionality, you also need to have the LSP
servers installed in your system. In the case of Go, it comes with the standard
toolchain, same as with Rust. For C, you will need clang, as far as I know GCC
doesn&#x27;t provide an LSP implementation.&lt;&#x2F;p&gt;
&lt;p&gt;The keybindings in my config make it so that I can go to definition with &lt;code&gt;gd&lt;&#x2F;code&gt;,
go to declaration with &lt;code&gt;gD&lt;&#x2F;code&gt;, get a popup with information implementations and
comment documentation with &lt;code&gt;gK&lt;&#x2F;code&gt;, rename variables with &lt;code&gt;&amp;lt;leader&amp;gt;n&lt;&#x2F;code&gt; (leader is
space in my config) and process the file through a formatting tool (e.g. gofmt)
with &lt;code&gt;&amp;lt;leader&amp;gt;b&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;other-plugins&quot;&gt;Other plugins&lt;&#x2F;h3&gt;
&lt;p&gt;Now, LSP provides most of the functions you would expect from an IDE, but there
are still some other plugins that I use for better quality of life. Namely:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;vim&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-vim &quot;&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;...
&lt;&#x2F;span&gt;&lt;span&gt;	Plug &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;ervandew&#x2F;supertab&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;	Plug &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;majutsushi&#x2F;tagbar&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;	Plug &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;#39;tpope&#x2F;vim-commentary&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first one, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ervandew&#x2F;supertab&quot;&gt;supertab&lt;&#x2F;a&gt;, makes using
autocompletion much more comfy. By default the omnifunc autocomplete is bound to
&amp;lt;C-x&amp;gt;&amp;lt;C-o&amp;gt; which is not very comfortable to enter. Usually, in shells and
other editors, you use Tab to autocomplete, which is a pretty sane way to do it.
But sometimes you actually need to insert tabs manually. That&#x27;s where this
plugin comes in, since it intelligently chooses whether to insert a tab, or
autocomplete on pressing the Tab key.&lt;&#x2F;p&gt;
&lt;p&gt;The next is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;preservim&#x2F;tagbar&quot;&gt;tagbar&lt;&#x2F;a&gt;. This plugin allows
you to open up a sidebar of sorts that lists the global variables,
data&#x2F;struct&#x2F;type definitions, and functions in the current source file. It
requires a ctags implementation to work.&lt;&#x2F;p&gt;
&lt;p&gt;Finally is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-commentary&quot;&gt;vim-commentary&lt;&#x2F;a&gt;, which
provides an easy way to comment out multiple lines easily. Not AS useful as the
other ones, but still handy nonetheless.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;debugging&quot;&gt;Debugging&lt;&#x2F;h2&gt;
&lt;p&gt;Sooner or later when writing programs and testing them you come across some kind
of programming error that causes it to misbehave. You can try to find the
problem manually by looking at the code and scratching your head, but a much
better way is to fire up a debugger and go step-by-step over the program
execution in search of your bug.&lt;&#x2F;p&gt;
&lt;p&gt;For some time, at least for C and other languages that are supported by it, I
would just open gdb in a different terminal window and keep my source file open
in vim in another. But a couple of additions were made to both vim and neovim
which made it much pleasurable to debug programs.&lt;&#x2F;p&gt;
&lt;p&gt;The first is &lt;code&gt;terminal&lt;&#x2F;code&gt; which, just as its name implies, is a terminal emulator
inside vim. Basically it allows you to open a terminal inside a vim buffer. For
me personally this feature by itself is not of great use, since I use a tiling
WM which already makes it much more comfortable for me to move around terminals.
However, it gives way to a plugin that is much more useful, and which depends on
this functionality.&lt;&#x2F;p&gt;
&lt;p&gt;Introducing &lt;code&gt;Termdebug&lt;&#x2F;code&gt;. This is a plugin which is built into both Vim (version&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;= 8.1) and Neovim. What it basically does is it opens two split windows, one
with gdb and the second one with the output of your program. You can then input
gdb commands directly into the gdb console, or through some vim-provided
shortcuts.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;In order to start using Termdebug, you need to first load the plugin:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;vim&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-vim &quot;&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span&gt;:packadd termdebug
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then load it providing the name of the binary that is going to be executed
by gdb:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;vim&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-vim &quot;&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span&gt;:Termdebug &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;path to binary&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You will be greeted with two new split buffers, one with the program output and
the other with a gdb console. They are both terminal buffers. The way you use
those terminal buffers in vim is, you enter insert mode to type into the
terminal, and exit insert mode with &amp;lt;C-\&amp;gt;&amp;lt;C-n&amp;gt;. Why not escape? Because
some terminal programs make use of escape, for example, vi mode in bash or zsh.
Or maybe even another vim instance inside vim, why not ¯\&lt;em&gt;(ツ)&lt;&#x2F;em&gt;&#x2F;¯.&lt;&#x2F;p&gt;
&lt;p&gt;After having opened Termdebug, you can run the program the classic way from gdb.
Or from within vim with &lt;code&gt;:Run &amp;lt;args&amp;gt;&lt;&#x2F;code&gt;. Other useful shortcuts are &lt;code&gt;:Break&lt;&#x2F;code&gt; to
set a breakpoint at the current line of code, &lt;code&gt;:Clear&lt;&#x2F;code&gt; to delete a breakpoint at
the current line if there&#x27;s any, &lt;code&gt;:Continue&lt;&#x2F;code&gt; to resume program execution, etc.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;debugging-in-vim&#x2F;debugging-session.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;debugging-in-vim&#x2F;debugging-session.png&quot; alt=&quot;A screenshot of an example debugging session&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;An example debugging session.&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;What makes this really wonderful is the fact that you see the process of
debugging straight in your source file. You don&#x27;t have to constantly list the
code inside gdb, and you can just navigate around files to set or clear
breakpoints.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, since you&#x27;re just debugging programs with gdb the usual rules of
debugging with gdb apply. For example, you need to compile your program with
debugging symbols, i.e. with the &lt;code&gt;-g&lt;&#x2F;code&gt; flag.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;afterword&quot;&gt;Afterword&lt;&#x2F;h2&gt;
&lt;p&gt;These are just of the plugins and configurations that use in vim to help me
write and debug software. This is, of course not meant as an in-depth tutorial
or guide on how to configure vim or how to properly debug programs. This is
just a mere guide on how one can use vim in conjunction with other tools to
develop and debug programs. There&#x27;s a lot of information on the internet on how
to configure vim or how to debug programs with gdb, and using other tools such
as valgrind and ASan.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to know more about lsp in neovim, you can read the help page inside
neovim by entering &lt;code&gt;:help lsp&lt;&#x2F;code&gt;. The same goes with Termdebugger: &lt;code&gt;:help Termdebugger&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you are interested, you can check my full neovim config here:
&lt;a href=&quot;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;configs&#x2F;vimrice&#x2F;&quot;&gt;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;configs&#x2F;vimrice&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;figcaption id=&quot;exit-vim&quot;&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;debugging-in-vim&#x2F;quit-vim.jpg&quot; alt=&quot;How to exit vim&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you have never used Vim before, and this article caused you to open it in a
whim and now you can&#x27;t exit it, this picture might be helpful.&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Not completely Unix-y, but somewhat adherent to the Unix philosophy in the
sense that one program should do one thing and do it right. A shock coming
from Microsoft, I know. You can learn more about it here:
&lt;a href=&quot;https:&#x2F;&#x2F;microsoft.github.io&#x2F;language-server-protocol&#x2F;&quot;&gt;https:&#x2F;&#x2F;microsoft.github.io&#x2F;language-server-protocol&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Why I don&#x27;t use social media</title>
		<published>2021-12-12T13:41:21+00:00</published>
		<updated>2021-12-12T13:41:21+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/social-media/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/social-media/</id>
		<content type="html">&lt;p&gt;Many friends sometimes find it strange that I do not use any social media,
besides instant messaging, if that counts. Very often I find that I keep
answering the same questions over and over again, so I&#x27;ve decided to write up my
thoughts on social media, and the reasons that I don&#x27;t use such platforms.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Even though I don&#x27;t have or use any social media platforms, I used to be
registered and was a somewhat active user of Facebook and VK&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Active in the
sense that I would login from time to time, and in the case of Facebook, I used
to use it as a sort of backup for my photos, so I would post them there. I never
found it particularly interesting to constantly post whatever I was doing. For
me, those platforms were useful only in the sense that they helped me keep in
touch with friends, family and other acquaintances.&lt;&#x2F;p&gt;
&lt;p&gt;I also used them to read up on some content in such platforms like news or
memes. Eventually, I realized that most of the content in such platforms was
worse than subpar and it was just distracting me from whatever I should be doing
at the moment. Even if I wasn&#x27;t doing anything at the moment, I realized that I
wouldn&#x27;t lose anything of value if I lost access to said content. So I stopped
using social media for that, and I would get my content from other sources,
which didn&#x27;t distract as much as social media and provided much better quality.&lt;&#x2F;p&gt;
&lt;p&gt;After some time, I found that I had less and less use for said platforms. I
unregistered&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; from Facebook right away, because it was the crappiest of the
platforms, but I kept using VK, because there were still some people that I had
to keep in touch with and was still tolerable, until it was not.&lt;&#x2F;p&gt;
&lt;p&gt;The only use that I had for them was instant messaging. However, most of the
people I actually care about and with whom I constantly keep in touch are using
Telegram&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. So I stopped using social media altogether.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, these reasons are mostly superficial. There are other aspects of
social media that when put together made me actually consciously drop their use.
Whereas before I considered social media a necessary evil that was kind of
useless in its own, but necessary because of networking effects and the way our
society works nowadays, now I consider social media not only useless, but
actually malign.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-problems-with-social-media&quot;&gt;My problems with social media&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;privacy-or-lack-thereof&quot;&gt;Privacy, or lack thereof&lt;&#x2F;h3&gt;
&lt;p&gt;This is probably the biggest problem, yet many people either don&#x27;t realize
social media has a privacy problem or they don&#x27;t think it is a problem. For
years, people have been warned about the problem that social media platforms
pose for our privacy, yet only recently&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; have people begun to realize that
all those warnings weren&#x27;t paranoia but well-founded concerns&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, there seems to have been a shift in the value of privacy for
many people. It seems as if big corporations and governments have successfully
convinced people that privacy shouldn&#x27;t hold any value for them since, after
all, &quot;you shouldn&#x27;t worry if you have nothing to hide&quot;™. Yet if you talk with
most people, even if they say that they don&#x27;t care, they won&#x27;t give away private
information to just anybody, and there&#x27;s certain information that they won&#x27;t
give away even to their most trusted friends or their spouses. That is, however,
a topic for another post.&lt;&#x2F;p&gt;
&lt;p&gt;In the end, the business models of most of these platforms relies on the
constant violation of your privacy. That&#x27;s another reason why they will try and
convince you, that this violation of one of your essential rights is beneficial
to you.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;control-and-manipulation&quot;&gt;Control and Manipulation&lt;&#x2F;h3&gt;
&lt;p&gt;This is an issue that goes very much in hand with the privacy issue. Social
media platforms are run and governed by centralized organizations, i.e
corporations, or governments in some cases. Not only can these organizations
decide what gets censored and what is allowed, but they also have the ability to
manipulate in which way the information is presented.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of Facebook and YouTube, for example, there&#x27;s an algorithm that
decides what gets more visibility and what gets delegated to obscurity. Nobody
outside of Facebook or Google actually knows how this algorithm operates, yet it
is what decides what the people in said platforms get to see. And these
algorithms have been shown to have greater biases towards certain kinds of
content or information.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s also the case of filtering content for deeming it to be
&quot;disinformation&quot;. It might seem like a noble thing to do, but you cannot trust
these big entities to act on your best interests, and more often than not, the
information that they censor or label as &quot;fake&quot; or &quot;bad&quot; is information that
just goes against their favored narrative. It is the right and duty of each
person to use their mental faculties to decide for themselves what constitutes
factual or desirable information, not some central authority. This is no better
than the government censorship to which many countries are still subject
nowadays and which, ironically, these corporations often decry.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bad-habits&quot;&gt;Bad habits&lt;&#x2F;h3&gt;
&lt;p&gt;This one is probably more subjective, but it has been my observation that social
media tends to have more of a negative effect on people, rather than a positive
one.&lt;&#x2F;p&gt;
&lt;p&gt;The reason most people keep using social media, and this is especially true of
women, is that they can satisfy, albeit in an artificial and meaningless way,
some of their emotional needs. It can be just plain vanity or ego, seeing people
react, especially positively, to your posts sure boosts your ego. It&#x27;s not a
coincidence that most mainstream social media don&#x27;t have a dislike or equivalent
button.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;social-media&#x2F;insta-posers.jpg&quot; alt=&quot;Oh look at me! I am so enjoying this beach, and totally not posing just to seem interesting, and there are totally not other 3 girls doing the same thing next to me&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;figcaption&gt;
&lt;p&gt;An example of social-media-induced degenerate behavior in the wild.
&lt;a href=&quot;https:&#x2F;&#x2F;old.reddit.com&#x2F;r&#x2F;funny&#x2F;comments&#x2F;92tw8e&#x2F;i_was_stood_taking_a_photo_of_my_girlfriend_in&#x2F;&quot;&gt;Source&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;figcaption&gt;
&lt;p&gt;Now there are a lot of people that seem to be living their lives through a proxy
called social media. Or rather, it would seem as if their life has become social
media. They can&#x27;t just enjoy a night out at a restaurant with friends, they must
photograph every dish and every little detail of their table so that they can
prove to other people on the internet that they have an &quot;interesting&quot; life. Then
they spend their time buried in their phones waiting for people to react to
whatever they posted.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s also the gossip aspect of social media. Now it is not enough to go about
gossiping in real life. People attached to social media seem to have an
unhealthy need to &quot;know what&#x27;s going on&quot;. It&#x27;s as if not knowing what Alice or
Bob did means the end of the world.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, there is also the blind following of &quot;influencers&quot;. This is not a
problem exclusive of social media, but it certainly has been exacerbated by it.
The voice or opinion of certain people or group of people is made more important
not by what they have to say or the actual merit of their actions or words, but
by how big of a following they have.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;it-s-just-useless&quot;&gt;It&#x27;s just useless&lt;&#x2F;h3&gt;
&lt;p&gt;If somehow all forms of electronic correspondence, such as email and instant
messaging were to suddenly disappear, a lot of people would suddenly find
themselves in a problematic situation. Nothing that couldn&#x27;t be managed, but it
would certainly be troublesome. If, on the other hand, the same were to happen
to all social media, e.g. Facebook, Twitter, Instagram, etc.; nothing of value
would be lost.&lt;&#x2F;p&gt;
&lt;p&gt;There are of course some arguments that could be made in favor of social media,
but I believe that all of these supposed benefits can be had without social
media:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It helps me keep in touch&lt;&#x2F;strong&gt;: we&#x27;ve already had email and instant messaging
for quite a while, actually before social media, not to mention both mobile
and landline phones. All of those are much better alternatives in many
different ways.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;How would I keep people up to date on some information&lt;&#x2F;strong&gt;: if you actually have
something worth sharing, the best option is to keep a blog. If you are not
technically savvy there are always free blogging options that don&#x27;t require any
special knowledge to use. Of course, if you have the skills, or the time to
learn the skills, the best option would be to host your own website&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;How do I keep up to date with what people have to say&lt;&#x2F;strong&gt;: Analogous to the
previous point, if somebody has something worth reading or watching, they
should post it to their own blog or website. Furthermore, there&#x27;s a great
technology that has been forgotten by most people that works in a fashion
similar to social media feeds, RSS&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#7&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, except you don&#x27;t actually need an
account and you control the information that you get.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;I want my friends to know what I&#x27;m doing&lt;&#x2F;strong&gt;: touch some grass, &#x27;nuff said.
But seriously, just get together with your friends and, tell them what&#x27;s been
going on with your life. Or if you can&#x27;t, give them a call or text them.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;I run a business and to promote it&lt;&#x2F;strong&gt;: Of all the pros of social media that I
have heard or could come up with, this is the only one that has some merit. In
this case I would suggest promoting your business locally first, and keeping a
website for your business through which people can follow any new information
about new products&#x2F;services or special promotions. In the end, word of mouth
is the best tool businesses have to promote themselves.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;in-conclusion&quot;&gt;In conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Most of what I wrote here have been my opinions and observations that have led
me to decide to don&#x27;t use social media at all. I never had any real use for it
and kept it mostly as something that was expected of me for a while. In the end
I just decided that there&#x27;s no reason I should actually have a social media
account.&lt;&#x2F;p&gt;
&lt;p&gt;With all of the above said, I know most people will continue to use social media
just because it&#x27;s what all their friends are using and it provides a
superficially pleasant service. These are just my reasons why I refuse to use
said services. If this text convinced you to stop using social media, great; if
not, fair enough, but just keep in mind that you can&#x27;t expect everybody to use
those platforms.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;If you don&#x27;t count instant messengers as social media.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Boy do they want your data really bad. Deleting my Facebook account has
been one of the worst and most tedious experiences I&#x27;ve ever had in my life.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;I don&#x27;t consider Telegram to be the best option for IM communication out
there, it&#x27;s just he lesser evil option that I could choose for the time being,
certainly much better than WhatsApp, Viber or VK. Almost nobody that I know
uses Signal, and it&#x27;s centralized anyway; Matrix seems like a nice option, but
their problems with metadata leakage put me off; XMPP seems like the best
option for decentralized, E2EE, truly private IM, but I&#x27;m not sure if my
&quot;normie&quot; friends would be willing to switch. This footnote is already long
enough, but I will definitely switch to a decentralized, E2EE IM in the
future, and might write about it here.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;As usual, Stallman was right. To paraphrase him: “Facebook doesn&#x27;t have
users, it has &quot;useds&quot;”. &lt;a href=&quot;https:&#x2F;&#x2F;www.stallman.org&#x2F;facebook.html&quot;&gt;https:&#x2F;&#x2F;www.stallman.org&#x2F;facebook.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;See the somewhat recent scandal surrounding Facebook and Cambridge
Analytica for some examples.
&lt;a href=&quot;https:&#x2F;&#x2F;www.theguardian.com&#x2F;technology&#x2F;2018&#x2F;mar&#x2F;17&#x2F;facebook-cambridge-analytica-kogan-data-algorithm&quot;&gt;https:&#x2F;&#x2F;www.theguardian.com&#x2F;technology&#x2F;2018&#x2F;mar&#x2F;17&#x2F;facebook-cambridge-analytica-kogan-data-algorithm&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;I might write an article on some the ways you can easily set up your own
website and&#x2F;or server. In the meantime, you can check out this great resource:
&lt;a href=&quot;https:&#x2F;&#x2F;landchad.net&#x2F;&quot;&gt;https:&#x2F;&#x2F;landchad.net&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;7&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;Technically Atom is the superior format, but most people (myself included)
refer to both of them as RSS, and basically all modern RSS readers support
both equally. Maybe I&#x27;ll write about (I keep saying that too much) RSS&#x2F;Atom in
the future.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>New computers suck</title>
		<published>2021-04-10T22:07:52+00:00</published>
		<updated>2021-04-10T22:07:52+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/new-computers-suck/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/new-computers-suck/</id>
		<content type="html">&lt;p&gt;Recently my T480 started having some motherboard problems that prevented the
keyboard from working correctly. I needed to repair it, but I couldn&#x27;t afford to
wait while it is being repaired since I need it for my work and studies, and
being a motherboard problem, it wasn&#x27;t even a fact that it could be repaired,
without having to replace the entire motherboard. So, I decided to buy a cheap
used computer and use that for the time being.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;In our day and age there is this general believe that progress, whatever that
means, is the one thing that we should strive for, and by consequence every new
thing is better than the older thing it is meant to replace. While there is
certainly improvements in some areas, new things are, very often, not an overall
improvement over the old things that they were meant to replace. Especially if
we are talking about durability and repairability, but those are far from the
only aspects where new hardware has regressed.&lt;&#x2F;p&gt;
&lt;p&gt;This article is basically my review of two computers, both ThinkPad, the old but
venerable X200 and its more modern cousin the T480, followed by a comparison of
the two and my conclusions on whether new hardware is really worth it.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re not really interested in reading a detailed review of each computer,
you can skip ahead to the &lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;new-computers-suck&#x2F;#modern-vs-old&quot;&gt;comparison&lt;&#x2F;a&gt;. You can also skip
directly to the &lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;new-computers-suck&#x2F;#t480&quot;&gt;review of the T480&lt;&#x2F;a&gt; or the &lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;new-computers-suck&#x2F;#x200&quot;&gt;review of the X200&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;backstory&quot;&gt;Backstory&lt;&#x2F;h2&gt;
&lt;p&gt;I got my T480 at my previous job in 2019. It is quite the machine with an 8th
gen Core i7 with 8 threads and a 512 NVMe SSD. However, it seems that Lenovo, as
many other computer (and not only) manufacturers seem to be going down in
quality.&lt;&#x2F;p&gt;
&lt;p&gt;First, it died on me about a year ago. It just wouldn&#x27;t turn on. Fortunately, it
still had its warranty, so I turned it in for a warranty repair. After about two
weeks in the Lenovo repair shop I got my machine back with a replacement
motherboard, and also a new frame and shell for the display, since the original
one had started to fall off a little on the bottom sides. I&#x27;ll talk about those
minor quality problems a little later.&lt;&#x2F;p&gt;
&lt;p&gt;Then, almost four weeks ago, I started to have problems with my keyboard. At
first they were intermittent, but as time went on they got more persistent, to
the point that it was no longer possible to have any work done without becoming
frustrated. The problem was that some keys on the keyboard refused to work. I
bought a replacement keyboard and replaced it immediately. To my unpleasant
surprise, I had the exact same problems with the new keyboard as with the old
one, meaning that it was actually a problem with the motherboard. Another
indication that the problem is with the motherboard, is that if I slightly push
or bend the body of the laptop, the keys start working.&lt;&#x2F;p&gt;
&lt;p&gt;At this point I was pretty disappointed with the quality of this laptop. Not
only did it have some minor quality problems, but it had also had two major
problems that fully or partially impeded the correct functioning of the machine.
That, and as I mentioned in the introduction, I didn&#x27;t have the time for a
repair, so I ended up buying a cheap old laptop.&lt;&#x2F;p&gt;
&lt;p&gt;The machine I ended up buying was a venerable ThinkPad X200. I had heard a lot
of good things about old ThinkPads, and after almost three weeks of use, I can
certify that they are indeed pretty damn good laptops. I&#x27;ll first talk a little
about the T480, then I&#x27;ll review the X200, and finally I&#x27;ll summarize their pros
and cons.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;t480&quot;&gt;T480&lt;&#x2F;h2&gt;
&lt;p&gt;This is a pretty modern machine, having been released in 2018. I have actually
enjoyed using it, since overall it is actually quite a good machine, much better
and comfortable to use than most laptops of its era.&lt;&#x2F;p&gt;
&lt;p&gt;It was acquired new in 2019 and cost around $1600 USD without the dock included.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;computing-performance&quot;&gt;Computing performance&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Core i7-8650U 4 cores @ 1.90 with 2 threads per core&lt;&#x2F;li&gt;
&lt;li&gt;16GB DDR4 RAM&lt;&#x2F;li&gt;
&lt;li&gt;512GB NVMe PCI SSD&lt;&#x2F;li&gt;
&lt;li&gt;14&quot; 2560x1440 IPS matte display&lt;&#x2F;li&gt;
&lt;li&gt;Intel UHD Graphics 620&lt;&#x2F;li&gt;
&lt;li&gt;Nvidia MX150 2GB&lt;&#x2F;li&gt;
&lt;li&gt;24Wh internal battery + 24Wh external battery&lt;&#x2F;li&gt;
&lt;li&gt;Weight 1620g&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Obviously the specs are one of the best qualities of this laptop. I don&#x27;t &quot;game&quot;
on my laptop, and Novidya has pretty crapy drivers on Linux that aren&#x27;t
compatible with Sway (my WM of preference), so I ended up just not installing
any drivers for the Nvidia card. The only downside to that, at least for me, is
that I cannot get audio out through the HDMI port.&lt;&#x2F;p&gt;
&lt;p&gt;So in terms of raw computing power it is a pretty capable machine. I am able to
playback up to 4K@30fps videos without any hiccups. Any higher FPS and it might
begin to drop frames, especially if the bitrate is high.&lt;&#x2F;p&gt;
&lt;p&gt;I never really use up all of the memory, unless I am doing some highly intensive
taks like compiling, since I use good and non-bloated software on my computer.
There&#x27;s some exceptions of course, like my browser, since there are no
non-bloated browsers due to the bloated nature of the web in general.&lt;&#x2F;p&gt;
&lt;p&gt;The processor is also quite capable, being able to compile the Linux kernel in
around 5-10 minutes. Even on battery it is quite fast.&lt;&#x2F;p&gt;
&lt;p&gt;The biggest bottleneck usually is the storage device, but with the SSD on this
machine I was able to boot to the GUI in under 9 seconds with an encrypted root.
That is not counting the BIOS&#x2F;UEFI loading time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;display&quot;&gt;Display&lt;&#x2F;h3&gt;
&lt;p&gt;The display on my configuration is quite good. It is certainly not the best out
there, especially if compared to Macbook displays, but it does provide quite
vivid and colorful images at a great resolution. It is quite bright, around
300-350 nits, and covers around 98% sRGB.&lt;&#x2F;p&gt;
&lt;p&gt;With the fractional scaling capabilities of Sway, everything Wayland native
rendered with pretty good detail and clarity, especially fonts.&lt;&#x2F;p&gt;
&lt;p&gt;With all of that said, it is not a display that I would put in a productivity
laptop. The reason, it has the atrocious 16:9 aspect ratio. Why oh why is this
aspect ratio still the dominant one on computers. The only place for this aspect
ratio is TVs, it has no place on computers, especially ones that are meant for
productivity. Even Apple gets it, why can Macbooks have 16:10 displays, but
ThinkPads, &quot;business&quot; laptops, don&#x27;t? Seriously, Lenovo.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;power-consumption-and-thermals&quot;&gt;Power consumption and thermals&lt;&#x2F;h3&gt;
&lt;p&gt;More than raw computing power, for me, the more important improvement when it
comes to computing is power efficiency. I can say that this laptop is quite
power efficient. Using powertop[^1], at about 50% display brightness (quite
bright indoors), and with mild usage such as web browsing, music listening, and
editing text, it uses around 4-8 Watts which yields about 6-8 hours of usage,
quite enough for my needs.&lt;&#x2F;p&gt;
&lt;p&gt;One really good thing about this laptop, is that, if I ever needed more battery
power, I could buy another external battery with more capacity, and replace it
on the go without shutting down the laptop, because of the internal battery.&lt;&#x2F;p&gt;
&lt;p&gt;Thermals are also pretty decent. With the same average mild usage, the cooler
fan stays off, and the temperature hovers around 40-50ºC depending on the room
temperature. The palm rest doesn&#x27;t get hot, and only the bottom gets warm
enough to notice, but without any discomfort. Even when the fan starts to work,
it is really quite, and only gets noticeably audible on high workloads, but
still quieter than other laptops such as Dells and Macbooks.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;input-devices&quot;&gt;Input devices&lt;&#x2F;h3&gt;
&lt;p&gt;The keyboard in this laptop is pretty good, even though it is a chiclet style
keyboard. It has decent travel distance, tactile feedback and it is not very
noisy. All in all it is the best laptop keyboard out of any other laptops of its
time.&lt;&#x2F;p&gt;
&lt;p&gt;The trackpoint is as good as they get. The fact that it is here is already a
good thing, since not many laptops have a trackpoint, even though it is such a
good pointing device, especially when you&#x27;re working with the keyboard most of
the time, as I do.&lt;&#x2F;p&gt;
&lt;p&gt;The trackpad is decent, but it could be improved (or maybe even removed). It is
big enough, not so big that it starts to get in the way, such as in Macs, but
big enough to be comfortable to use. The texture is also nice. I don&#x27;t use the
trackpad that much though, I mostly used it to scroll when reading in bed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;i-o-and-comms&quot;&gt;I&#x2F;O and comms&lt;&#x2F;h3&gt;
&lt;p&gt;Compared to most modern laptops it has a good array of ports, with the following
ports:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;2 USB 3.1 ports&lt;&#x2F;li&gt;
&lt;li&gt;1 USB 3.1 Type-C port&lt;&#x2F;li&gt;
&lt;li&gt;1 USB 3.1&#x2F;Thunderbolt 3 Type-C port&lt;&#x2F;li&gt;
&lt;li&gt;HDMI port&lt;&#x2F;li&gt;
&lt;li&gt;Gigabit Ethernet port&lt;&#x2F;li&gt;
&lt;li&gt;Smartcard reader&lt;&#x2F;li&gt;
&lt;li&gt;SD card reader&lt;&#x2F;li&gt;
&lt;li&gt;Headphone&#x2F;mic jack&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It might not be as a diverse and big array of port as on older computers, but it
is enough for my use case.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s also the ThinkPad dock stations, which offer a very comfortable way of
plugging in all devices and getting access to more ports at home or in the
office. I got the ThinkPad Pro Docking Station, which makes use of the two
Type-C ports on the left side to provide power and a plethora of ports:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;3 USB 3.1&lt;&#x2F;li&gt;
&lt;li&gt;2 USB 2.0&lt;&#x2F;li&gt;
&lt;li&gt;1 USB 3.1 Type-C&lt;&#x2F;li&gt;
&lt;li&gt;2 DisplayPort&lt;&#x2F;li&gt;
&lt;li&gt;Gigabit Ethernet&lt;&#x2F;li&gt;
&lt;li&gt;Audio out&#x2F;mic jack&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It is quite convenient as it is hot-pluggable and doesn&#x27;t require any special
configuration or drivers.&lt;&#x2F;p&gt;
&lt;p&gt;Regarding the comms, it comes with a WLAN card that supports WiFi 802.11ac at
both 2.4 and 5 GHz, and Bluetooth 4.1. My model also came with an LTE WWAN card,
although I have never had use of it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;serviceability&quot;&gt;Serviceability&lt;&#x2F;h3&gt;
&lt;p&gt;It is quite easy to service and replace parts on this computer, which already
puts it at an advantage over most modern laptops.&lt;&#x2F;p&gt;
&lt;p&gt;By just unscrewing two screws you can then lift up, disconnect and remove the
keyboard. By removing four more screws you can remove the bottom plate, and get
accesses to basically all of the components of the computer. You can replace the
storage drive, WLAN card, WWAN card, there&#x27;s two DDR4 RAM slots. The internal
battery can also be replaced.&lt;&#x2F;p&gt;
&lt;p&gt;The CPU and GPU are soldered to the board though, as in basically every laptop
nowadays.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chassis-and-build-quality&quot;&gt;Chassis and build quality&lt;&#x2F;h3&gt;
&lt;p&gt;The computer body is made of plastic materials that are nice to the touch. The
body doesn&#x27;t bend and creak on pressure from my palms and when lifting the
laptop from one side, as in other laptops I&#x27;ve owned. For the size of the laptop
it has a nice balanced weight, not very light, but not heavy either.&lt;&#x2F;p&gt;
&lt;p&gt;The hinges of the screen are also quite good, as they don&#x27;t wobble at all,
compared to other laptops. You can&#x27;t open the lid easily with one hand, not that
it is very important for me.&lt;&#x2F;p&gt;
&lt;p&gt;The internal chassis is made of metal, some magnesium allow I think, which is
supposed to make it more sturdy and protect it from outside forces. It is indeed
a more sturdy design than most laptops out there.&lt;&#x2F;p&gt;
&lt;p&gt;While the build quality overall is better than most laptops nowadays, it is
still lacking.&lt;&#x2F;p&gt;
&lt;p&gt;It is all mostly on the details, such as the keyboard, trackpad and trackpoint
leaving marks on the display that can&#x27;t be removed, just in the name of making
the computer thinner; I wouldn&#x27;t have minded a couple more millimeters of
&lt;strong&gt;thicc&lt;&#x2F;strong&gt;ness just to avoid having my display being scathed for life.&lt;&#x2F;p&gt;
&lt;p&gt;Another thing is that the frame of the display is just a flimsy piece of plastic
that is glued to the lid, which starts to come off pretty easily. Also a piece
of the palm rest chipped off, even though I have never dropped the laptop.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;audio&quot;&gt;Audio&lt;&#x2F;h3&gt;
&lt;p&gt;The speakers are not good, quite frankly, but the DAC on this computer seems to
be fine and I don&#x27;t get any noises from the audio jack. That said the audio jack
is a combo jack for out and microphone. I can&#x27;t stand these types of ports, they
are fine on mobile phones, but certainly not in a computer. Not to mention that
it already has worn out, resulting in the laptop detecting a microphone when
there is none.&lt;&#x2F;p&gt;
&lt;p&gt;A smaller complaint that I have, is that the port is placed on the right side of
the laptop. Being that 99% of headphones have the cable on the left earcup, I
can&#x27;t understand why most laptop designers can&#x27;t put in a little more thought
and put the damn jack on the left side.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;firmware-and-drivers&quot;&gt;Firmware and drivers&lt;&#x2F;h3&gt;
&lt;p&gt;Overall all devices, except for the fingerprint reader which I don&#x27;t use anyway,
work out of the box in Linux. The devices&#x27; firmware, including the UEFI, also
get updates through fwupd.&lt;&#x2F;p&gt;
&lt;p&gt;The Novidya card, of course, has crappy drivers. That said, there were build
without the Nvidia card, and had it been my choice I would have forgone the
card, since I don&#x27;t use it anyway.&lt;&#x2F;p&gt;
&lt;p&gt;The UEFI is kind of a mixed bag. On the one hand it generally works well, has
many configuration options, a diagnostics tool and you can even change the
splash image (as in most ThinkPads) although it is not very straight-forward.
However, the thing takes ages to load. My Linux installation with encrypted root
boots the same if not faster, and that&#x27;s not acceptable. It takes about 8-9
seconds to load, where it should take no more than 2 seconds. Not to mention,
as expected, that all of it is proprietary and there&#x27;s no Coreboot for this
machine, at least yet.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;x200&quot;&gt;X200&lt;&#x2F;h2&gt;
&lt;p&gt;For computer standards, this would be considered a pretty old machine, being
first released in 2008. That said, if you don&#x27;t need to do any intensive
computing this is still a pretty decent machine and even better in many regards
than any modern laptop.&lt;&#x2F;p&gt;
&lt;p&gt;One of the first models manufactured by Lenovo after the brand was bought from
IBM. It still preserves the classic feel of the IBM ThinkPads with specs that
are more than enough for most home, programming or office tasks.&lt;&#x2F;p&gt;
&lt;p&gt;I acquired it a couple of weeks ago for around $120 USD dock station included.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;computing-performance-1&quot;&gt;Computing performance&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Intel Core 2 Duo P8600 2 cores @ 2.401GHz&lt;&#x2F;li&gt;
&lt;li&gt;4GB DDR3 RAM expanded to 6GB, expandable to 8GB&lt;&#x2F;li&gt;
&lt;li&gt;480GB SATA SSHD (SSD + HDD hybrid)&lt;&#x2F;li&gt;
&lt;li&gt;12&quot; 1280x800 LCD CCFL-backlit matte display&lt;&#x2F;li&gt;
&lt;li&gt;Intel GMA 4500MHD&lt;&#x2F;li&gt;
&lt;li&gt;56Wh external battery&lt;&#x2F;li&gt;
&lt;li&gt;Weight 1520g&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Quite low specs for 2021, most &quot;tech enthusiasts&quot; would cry, but it is quite
capable nonetheless, unless you are planning on compiling something big like a
browser or the Linux kernel, or doing photo editing or video editing.&lt;&#x2F;p&gt;
&lt;p&gt;As far as daily computing tasks go, the processor in this thing handles it
mighty fine. Web browsing, text editing all work fine. Video playback is also
fine, being able to play videos without drops up to 1080p@30fps, not the best
for 2021 when we already have plenty of content in 4K and even 8K, but I don&#x27;t
use this computer to consoom, and 1080p is plenty most of the times. 60fps
without drops would have been nice, though.&lt;&#x2F;p&gt;
&lt;p&gt;The GPU is weak, so in many cases, such as the web browser, it is better to go
with software rendering.&lt;&#x2F;p&gt;
&lt;p&gt;The SSHD that came with laptop when I bought it from the previous owner works
quite well. It&#x27;s not the original disk, but whatever. It boots faster than my
desktop with a standard HDD. It is nonetheless and unsurprisingly slower than my
T480&#x27;s PCI SSD. I am planning on replacing with a SATA SSD in the future, but in
the meantime, it does its job.&lt;&#x2F;p&gt;
&lt;p&gt;Even the relatively low amount of RAM that it currently has installed (6GB, came
with 4GB), it is still plenty enough for most tasks.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;display-1&quot;&gt;Display&lt;&#x2F;h3&gt;
&lt;p&gt;The image quality on this display is atrocious. It is bleak, the contrast is so
low the blacks are gray, the color coverage is horrendous, and the viewing
angles terrible. The resolution is also not very high, but that&#x27;s not as big of
a deal especially in such a small display.&lt;&#x2F;p&gt;
&lt;p&gt;That said, it is 16:10 and &lt;strong&gt;not&lt;&#x2F;strong&gt; the pathetic 16:9 aspect ratio. That&#x27;s
already a big win in my book. I do plan on changing it to a better display, I&#x27;ve
seen that it is possible to change it for an AFFS display, and maybe even a LED
900p display.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;power-consumption-and-thermals-1&quot;&gt;Power consumption and thermals&lt;&#x2F;h3&gt;
&lt;p&gt;Being such an old laptop, the power consumption and thermals are not as good as
most modern laptops. It still managed to surprise me a little, since I was
expecting worse power consumption and especially higher temperatures.&lt;&#x2F;p&gt;
&lt;p&gt;Using powertop[^1], at about 80% display brightness (any lower in a well-lit
room becomes uncomfortable with its current display), and with mild usage (see
T480), it uses 11-16 Watts which yields about 3-4 hours of usage with its
current battery. Not ideal, but enough most days. I hope that a screen and SSD
upgrade help to lower the power consumption.&lt;&#x2F;p&gt;
&lt;p&gt;For its age thermals are pretty good. As with the T480 with average mild usage
it heats to around 40-50ºC, sometimes a little bit higher. Unlike the T480,
though, its cooler fan is on basically all the time. It is still very quiet, so
it doesn&#x27;t cause any distractions or annoyances. The body of this laptop can get
a little bit hot if doing more intensive tasks than web browsing or text
editing, such as watching Full HD videos.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;input-devices-1&quot;&gt;Input devices&lt;&#x2F;h3&gt;
&lt;p&gt;This is the best laptop keyboard I&#x27;ve ever typed on, &#x27;nuff said. It doesn&#x27;t beat
a mechanical keyboard, but it definitely beats any modern laptop keyboard. There
are probably other classic ThinkPad models with slightly better keyboards, but I
haven&#x27;t tested those out, so I can only compare this with other laptops I&#x27;ve
used, like my T480 and plenty of Dells, HPs, Acers, Asus and some Toshibas. It
has great key travel, sounds good without being loud, great tactile feedback,
and also a nice 7-row layout, with dedicated volume keys.&lt;&#x2F;p&gt;
&lt;p&gt;There is no trackpad on this laptop, but the trackpoint is still better than a
trackpad, so no big loss there. If you actually need accuracy, for example when
manipulating graphical elements in GIMP or Inkscape, a traditional mouse is
still a better option anyway.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;i-o-and-comms-1&quot;&gt;I&#x2F;O and comms&lt;&#x2F;h3&gt;
&lt;p&gt;It has plenty of ports, although it might lack more modern ports, such as HDMI:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;3 USB 2.0 ports&lt;&#x2F;li&gt;
&lt;li&gt;Ethernet port&lt;&#x2F;li&gt;
&lt;li&gt;VGA D-bus port&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Dedicated&lt;&#x2F;strong&gt; Headphone jack&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Dedicated&lt;&#x2F;strong&gt; Microphone jack&lt;&#x2F;li&gt;
&lt;li&gt;SD card reader&lt;&#x2F;li&gt;
&lt;li&gt;Expresscard expansion slot&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Quite good for such a small laptop. The person I bought it from also sold it to
me with a UltraBase dock station that includes the following ports:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;4 USB 2.0 ports&lt;&#x2F;li&gt;
&lt;li&gt;Ethernet port&lt;&#x2F;li&gt;
&lt;li&gt;VGA D-bus port&lt;&#x2F;li&gt;
&lt;li&gt;DisplayPort&lt;&#x2F;li&gt;
&lt;li&gt;Headphone jack&lt;&#x2F;li&gt;
&lt;li&gt;Microphone jack&lt;&#x2F;li&gt;
&lt;li&gt;Serial port with included DVD drive&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It is also hot-pluggable and besides those ports it also includes a charging
station for batteries and audio speakers that don&#x27;t seem to work under Linux.
The DVD drive also doesn&#x27;t seem to work under Linux.&lt;&#x2F;p&gt;
&lt;p&gt;As for the comms, it includes a WLAN card supporting 802.11n, and as a surprise
to me for a laptop so old, it also supports both 2.4 and 5 GHz networks. It also
has Bluetooth 2.1 and the ability to add a WWAN cellular card, but once more,
I&#x27;m not really in need of that.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;serviceability-1&quot;&gt;Serviceability&lt;&#x2F;h3&gt;
&lt;p&gt;This laptop has quite a lot of screws, however, I like that it is very modular
in its approach to servicing. Not only is the keyboard removable without having
to open apart the laptop itself, but also the hard drive; and the memory has its
own compartment with its own lid. To get to the motherboard you just need to
unscrew 9 screws and remove the keyboard and palm rest.&lt;&#x2F;p&gt;
&lt;p&gt;Alas, even this laptop has the CPU and GPU soldered to the motherboard.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chassis-and-build-quality-1&quot;&gt;Chassis and build quality&lt;&#x2F;h3&gt;
&lt;p&gt;The materials of the exterior body are not as different, at least to the touch,
as those on the T480. The materials feel great and sturdy. The exterior is
covered is a soft touch rubberized finish, and the palm rest and inner frame of
the display is a more standard plastic. This laptop also has an internal
magnesium allow chassis.&lt;&#x2F;p&gt;
&lt;p&gt;I must emphasize that the display frame feels very sturdy and doesn&#x27;t flex at
all, and the hinges are also sturdy with no wobble. It is a little easier to
open this laptop&#x27;s lid with one hand, although the latch might hinder that a
little bit. I am not sure if I like or not having a latch, maybe it is better
without, but I gotta admit I have some bias towards it mainly for nostalgic
reasons; also makes it feel a little bit sturdier somehow.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s no creak or bend of the body either, no matter how you hold the laptop.
The keyboard is of superb quality, doesn&#x27;t bend at all and doesn&#x27;t rattle.&lt;&#x2F;p&gt;
&lt;p&gt;I really only have good things to say about the build quality, although it might
have to do with having it used for just three weeks. That said, the fact that
this laptop is about 12 years old (almost half my age!) and theres no dents or
cracks and only slight scratches on the rubberized surface and other slight
marks of use, speaks volumes of its build quality. If I do end up finding
something to complain about, I might update this article in the future.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;audio-1&quot;&gt;Audio&lt;&#x2F;h3&gt;
&lt;p&gt;The audio in this laptop is bad in basically all fronts. It doesn&#x27;t even
withcome two speakers. Yes, it only has one speaker (mono). That wouldn&#x27;t be
that bad if it weren&#x27;t for a small buzz and other noises present when listening
some music or sounds through the headphone jack. That problem is also present
with the dock station&#x27;s jack, which leads me to think it&#x27;s a problem with the
DAC, which must be a piece of crap, or it might be badly isolated generating
noises from the other components of the computer.&lt;&#x2F;p&gt;
&lt;p&gt;Good thing I have a music player with a really good DAC that can double as an
external DAC for audio out. Also might end up making use of the fact that this
computer comes with an Expresscard expansion slot and buy an Expresscard
sound card.&lt;&#x2F;p&gt;
&lt;p&gt;I understand this is a business laptop mainly, but one would expected at least
clean sound from the audio out port.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;firmware-and-drivers-1&quot;&gt;Firmware and drivers&lt;&#x2F;h3&gt;
&lt;p&gt;Everything works out of the box with no extra configuration on Linux, which can
be expected of a laptop of this age.&lt;&#x2F;p&gt;
&lt;p&gt;This laptop doesn&#x27;t have UEFI, which I have already gotten used to with it&#x27;s set
of nice features such as the ability to boot Linux (EFISTUB) without bloated
GRUB or any other bootloader. It&#x27;s all good ol&#x27; BIOS with it&#x27;s ups and downs.&lt;&#x2F;p&gt;
&lt;p&gt;But, this laptop has a big advantage, and that is Coreboot and even Libreboot
support. I haven&#x27;t flashed the ROM chip of this laptop with Coreboot yet, but I
definitely plan on doing so as soon as I get my hands on a SOIC-8 clip. Also, I
should probably fix my T480 so that I can at least use it as a backup in case
everything goes wrong and my poor X200 ends up exploding. I might even write
about my experience in the future.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;modern-vs-old&quot;&gt;Modern vs old&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;new-computers-suck&#x2F;t480-v-x200.jpg&quot; alt=&quot;T480 and X200 side by side&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now that I have reviewed each computer separately I will be comparing them in
each category I&#x27;ve reviewed them to see which is the better one overall.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;computing-performance-2&quot;&gt;Computing performance&lt;&#x2F;h3&gt;
&lt;p&gt;Well, there&#x27;s obviously no contest in this one, there isn&#x27;t even a reason to
compare a top of the line two year old model, with a 12 year old model. That
said, it really is enough for my productivity needs.&lt;&#x2F;p&gt;
&lt;p&gt;As you might have guessed, I am using Linux. On a cold boot to my WM I am only
using around 200MB of RAM and most of the programs I use for productivity and
even consoomption are really lightweight so I very rarely have any noticeable
lags that would distract me, if ever. Of course, if you are using something like
Windows 10, which uses around 2GB-3GB on a cold boot and is full of bloat, you
might not have such a good experience. Even Windows 7 is bloated compared to
Linux using around 1.5-2GB on a cold boot.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, anybody would be better using even a newbie Linux distro such as Mint
and even on a modern machine, rather than Winbloat, and for other obvious
reasons besides performance. I am just not expecting that &quot;normies&quot; will switch
operating systems, they will use whatever comes with their PC.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: T480&lt;&#x2F;p&gt;
&lt;h3 id=&quot;display-2&quot;&gt;Display&lt;&#x2F;h3&gt;
&lt;p&gt;This one is a hard for me to decide, since the screen on the T480 has really
good image quality with a high resolution which is miles ahead of the poor
quality panel on the X200, while the T480&#x27;s 16:9 aspect ratio sucks compared to
the better (yet improvable) 16:10 aspect ratio of the X200.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: DRAW&lt;&#x2F;p&gt;
&lt;h3 id=&quot;power-consumption-and-thermals-2&quot;&gt;Power consumption and thermals&lt;&#x2F;h3&gt;
&lt;p&gt;This one is also quite obvious. My T480 consumes on average around 3 times less
energy than my X200, which of course also translates into less heat, although
not that big a difference. This, I would say, is the biggest advantage of modern
laptops against older ones.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: T480&lt;&#x2F;p&gt;
&lt;h3 id=&quot;input-devices-2&quot;&gt;Input devices&lt;&#x2F;h3&gt;
&lt;p&gt;The trackpoint hasn&#x27;t changed in quality much if at all. The keyboard is a
different story. The keyboard on the T480 is good, but it just doesn&#x27;t compare
to the classic ThinkPad keyboard, which is present on the X200. From the layout
to the form of the keys to the travel distance and the tactile feedback.
Everything is just better on the X200&#x27;s keyboard. This is the one part that
suffered in quality just because of trends, which is ridiculous.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: X200&lt;&#x2F;p&gt;
&lt;h3 id=&quot;i-o-and-comms-2&quot;&gt;I&#x2F;O and comms&lt;&#x2F;h3&gt;
&lt;p&gt;They both have a good array of IO ports and good comms, but of course, being
that the comms and ports on the T480 support newer standards, it means that it
has got the advantage. That, and also the fact that it has two USB Type-C ports
on of which is Thunderbolt, meaning that you don&#x27;t rely on a proprietary port to
be able to connect your computer to a dock or hub. The ThinkPad docks are still
a better fit for them and they are better than most docks or hubs out there, but
it is always to have options and not having to rely on proprietary technology
that is only supported by one company, and which obviously loses support much
faster than open standards.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: T480&lt;&#x2F;p&gt;
&lt;h3 id=&quot;serviceability-2&quot;&gt;Serviceability&lt;&#x2F;h3&gt;
&lt;p&gt;They are both pretty easy to open to clean and maintain or replace any parts
that might need an upgrade or repair. However, I think the modular approach to
the disassembly of the X200 is slightly better than the approach on the T480.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: X200&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chassis-and-build-quality-2&quot;&gt;Chassis and build quality&lt;&#x2F;h3&gt;
&lt;p&gt;Well, I&#x27;ve already written plenty on the materials and build quality of both
machines in their respective reviews above. The X200 is just miles ahead in this
respect.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: X200&lt;&#x2F;p&gt;
&lt;h3 id=&quot;audio-2&quot;&gt;Audio&lt;&#x2F;h3&gt;
&lt;p&gt;Both have poor quality speakers, which I don&#x27;t really care too much about, but
the noise problem with the jack on the X200 is a big no-no.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: T480&lt;&#x2F;p&gt;
&lt;h3 id=&quot;firmware-and-drivers-2&quot;&gt;Firmware and drivers&lt;&#x2F;h3&gt;
&lt;p&gt;The UEFI loading times suck on the T480. The X200 has an old but good enough
BIOS. But. I can flash Coreboot and Libreboot on the X200 and get rid of the
Intel &lt;del&gt;Malware&lt;&#x2F;del&gt; Management Engine.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Winner&lt;&#x2F;strong&gt;: X200&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;If we count each comparison category equally they seem to be pretty close. In
the end it will depend on what you need the laptop for. In my case, if I didn&#x27;t
have a laptop at all right now, and I had to buy myself one, I would buy the
X200 or another old ThinkPad of similar caliber: great build quality, superb
classic keyboard, corebootable.&lt;&#x2F;p&gt;
&lt;p&gt;I recommend the X200 or a similar old ThinkPad to most people that use a
computer for daily productivity or internet tasks, not limited to but such as:
email, web browsing, text editing, school&#x2F;college stuff, programming. I mean,
buying a ~$1600 new computer doesn&#x27;t make sense when you can buy a computer for
~$120 that is of same use for you, but with a better keyboard and build quality.&lt;&#x2F;p&gt;
&lt;p&gt;Buy a brand-new computer only if you really need the computing power, if you
really need to squeeze as much battery life as possible without having to buy
multiple battery packs or if you need a display that has good color
reproduction for things such as photo editing. I, for example, obviously don&#x27;t
do my photo editing on the X200, I have a desktop with a decent monitor for
that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;epilogue-modern-software-also-sucks&quot;&gt;Epilogue: modern software also sucks&lt;&#x2F;h2&gt;
&lt;p&gt;Many people have this idea that with time old computers slow down. Indeed
computers do seem to slow down over time. It is not the hardware itself that
slows down or becomes less capable, unless it actually breaks, it is a problem
with newer software becoming more and more bloated, of which proprietary
software is the biggest offender.&lt;&#x2F;p&gt;
&lt;p&gt;It seems like the production of newer more powerful hardware just breeds more
and more soydevs that, thanks to the advancements in computing power, can hide
the slowness and bloatness of their horrible code among layers of abstractions
that execute just as fast (or rather slow) as good written software on older
machines. You don&#x27;t need a Threadripper or Core i9 or even a super modern Core
i3 to do basic daily computing tasks. If you use good software, that is, and
most of the times it is libre software.&lt;&#x2F;p&gt;
&lt;p&gt;Proprietary software is not only worse from an ethical point of view, but it is
also worse from the point of view of quality most of the times (with some minor
exceptions). As time goes on, proprietary software gets worse, because they just
care about launching the next version with the next new &quot;features&quot; as soon as
possible to get even more money in the shortest amount of time possible.&lt;&#x2F;p&gt;
&lt;p&gt;There are many other reasons why modern proprietary software is just plain worse
than minimal free and open source software, but this is already beyond the scope
of this article. Maybe I&#x27;ll write about my thoughts on modern software, and
proprietary and libre software in the future.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Fixing terminal and remote machine misunderstandings</title>
		<published>2021-03-27T16:10:01+00:00</published>
		<updated>2021-03-27T16:10:01+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/fix-broken-terminal-ssh/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/fix-broken-terminal-ssh/</id>
		<content type="html">&lt;p&gt;If you are like me and use a not-so standard terminal emulator and find yourself
frequently ssh&#x27;ing into new machines, or maybe you&#x27;ve changed your terminal
emulator, then this article might help you get your terminal fully functional
over ssh.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Upon logging in you might notice that several shell features might not work as
expected; clear does nothing, pressing backspace doesn&#x27;t erase the text on
screen, etc. Or trying to use a program like tmux you might come across a
message like &lt;code&gt;open terminal failed: missing or unsuitable terminal: &amp;lt;your terminal&amp;gt;&lt;&#x2F;code&gt;. This means that the system you&#x27;ve just logged into doesn&#x27;t know how
to interact with your terminal emulator.&lt;&#x2F;p&gt;
&lt;p&gt;This happens to me on a somewhat regular basis but not frequent enough to
remember how to solve it, and for some reason it is not easy to find the nice
answer I was looking for on the Internet, and so, I decided to write this to
help me remember how to properly solve this problem.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;&#x2F;h2&gt;
&lt;p&gt;The way I solve this is to first generate the terminfo description file on my
local computer. Let&#x27;s say I am using Alacritty:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ infocmp alacritty &amp;gt; alacritty.terminfo
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then copy that file to the remote machine, for example, using rsync:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ rsync alacritty.terminfo remote:
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally on the remote machine import the terminfo file. If you have root access,
you can import using root&#x2F;sudo so that it is available to all users, otherwise
it will only be available for the user you&#x27;re currently logged-in as.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# tic -x alacritty.terminfo
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are several other solutions (and some hacks) like copying the terminfo
directly from your &lt;code&gt;&#x2F;lib&#x2F;terminfo&#x2F;…&lt;&#x2F;code&gt; directory to the remote machine&#x27;s. I,
however, find the solution presented above to be cleaner and handier, since I
usually keep the terminfo file I generated with &lt;code&gt;infocmp&lt;&#x2F;code&gt; in case I need to
import it into any other machines, unless I change my terminal, in which case I
regenerate it first.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>A Viral Year</title>
		<published>2021-01-17T13:41:21+00:00</published>
		<updated>2021-01-17T13:41:21+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/a-viral-year/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/a-viral-year/</id>
		<content type="html">&lt;p&gt;The year 2020 has come and gone. I can&#x27;t say that it was a really bad year for
me in particular, but I am pretty sure that many, if not most people, are glad
it is over. I have never really &quot;reviewed&quot; a year, but the things that happened
during this year got me thinking about many things, and so I&#x27;ve decided to write
some of my thoughts on what twenty-twenty has brought upon us.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Even though overall last year was pretty good for me in many regards, the things
that happened, and most importantly, how most of the world reacted to the
situation at hand did unsettle me a little.&lt;&#x2F;p&gt;
&lt;p&gt;Everybody at this point knows the story. A mysterious virus that was discovered
first in China back in October 2019 starts spreading itself at an incredible
rate, and by March 2020 it&#x27;s spread all around the world. And so, as it spread,
the world started to lock down. I am completely convinced of the threat that
this virus poses. I am, however, not convinced that the measures that were taken
to &quot;combat&quot; this virus actually correlate to the real danger that it poses, nor
am I convinced that the blatant denial of people rights and liberties is
justified by it.&lt;&#x2F;p&gt;
&lt;p&gt;I actually caught the virus back in November (thanks to my roommate), and I can
tell you with complete confidence that if you are a healthy and young person,
you don&#x27;t have anything to worry about. Basically my symptoms were the
following:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Two days of 38C (about 100F(reedumbs units)) fever.&lt;&#x2F;li&gt;
&lt;li&gt;About four days of slight body pain and fatigue.&lt;&#x2F;li&gt;
&lt;li&gt;Slight decrease in taste&#x2F;smell perception while the symptoms lasted.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;My treatment consisted of the following: plenty of rest. And that&#x27;s it. Just 4
days of discomfort and then I was back to normal.&lt;&#x2F;p&gt;
&lt;p&gt;I wouldn&#x27;t actually have known that it was the &#x27;rona, had it not been that the
circumstances I was in forced me to I take the test. And because of the fact
that I took the test and I got a positive, and the regulations in place where I
currently live, I couldn&#x27;t leave my dormitory room de jure, until three weeks
after my first symptoms when I took the second test that fortunately turned out
negative.&lt;&#x2F;p&gt;
&lt;p&gt;Everybody&#x27;s body reacts differently to the virus. For example, I didn&#x27;t lose my
sense of smell&#x2F;taste completely, but my roommate and another friend that got it
did. For me the symptoms lasted about 4 days, for my friend they lasted a little
over a week. However, the people that I know that had it bad, were people who
either were 60+ years old, or that already had some medical conditions, or a
combination of the two.&lt;&#x2F;p&gt;
&lt;p&gt;This virus is in general deadlier than the common flu, and most importantly and
what makes it more dangerous, is the fact that it spreads so fast. The problem
is that the &quot;cure&quot; that we&#x27;re being fed up, is worse than the illness.&lt;&#x2F;p&gt;
&lt;p&gt;The government should give the people the tools to be prepared, and inform the
people the best it can. The people, that is, individuals, should then make use
of their freedom to make their own informed risk assessments, and take the
necessary precautions that they see fit given their own individual situation.
Instead of that, we have governments all around the world instituting draconian
measures that erode the basic rights of individuals, for the supposed safety
and security of the &quot;community&quot;. In reality in turns out the majority of people,
who aren&#x27;t really greatly affected by this virus, are giving up their liberties,
in order to &quot;protect&quot; the minority of people to whom this virus actually poses a
danger.&lt;&#x2F;p&gt;
&lt;p&gt;Do we ban &quot;extreme sports&quot; like snowboarding, because some people might, and do
die while practicing it? Of course not. We inform people of the dangers and
risks that it poses to them, and each person then decides if they risk their
health and probably lives, based on several factors, such as physical condition,
whether it is worth it risking their health for some fun, etc.&lt;&#x2F;p&gt;
&lt;p&gt;All these measures that have been imposed on us — at least in the countries with
the most draconian measures, i.e. most of the world — have been at the very
least dubious in their effectiveness, and I think the best example we have for
how dubious they are has been Sweden.&lt;&#x2F;p&gt;
&lt;p&gt;Sweden has taken a very lax and liberal approach to combat this epidemic, opting
to impose light-handed measures including restricting mass gatherings, but it
never implemented any real &quot;lock-downs&quot; on the level we have seen most
countries. And for this, they have unleashed upon themselves the wrath of the
&quot;wokes&quot; all around the world, with predictions that the lack of tougher measures
will mean a catastrophe for Sweden in the near to mid future. Not surprisingly,
the heaviest criticism has come from non other than one of the least free
countries of the world — China&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I, however, fail to see how this lenient approach on relying on the good
judgment of the citizens has been worse than that of countries with strict
lock-downs in place. The situation in Sweden does not look grimmer than in
countries with some of the toughest lock-down and restricting policies in place,
e.g. The UK, Spain, France, etc. The cases per million are pretty similar, and
the number of dead relative to the number of cases is basically the same as any
other developed country (around 2%)&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s not surprise that the most oppressive measures have been put in place in
big cities. After all, as has been for many years since the appearance of the
first polises, living in a city has meant trading in some liberties and
independence, in exchange for living in an orderly society, and of course, to
gain access to increased wealth, security and opportunities. It&#x27;s just a matter
of balance, and how much this possible &quot;increase in wealth&quot; is worth to you.
However, the recent events, have made me consider that lately the balance of the
liberties you are giving up has been increasing, outweighing the purposed
benefits of living in the city. This global crisis has just bluntly demonstrated
it by accelerating what was already happening in most parts of the world, and
providing us with a stark contrast. Especially considering that this crisis has
just accelerated the &quot;virtualization&quot; of a lot of our society. If you are forced
to make use of the benefits of the city by going online, and you can make use of
them wherever you have an internet connection, then what&#x27;s the benefit of living
in the city anymore?&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s not to say that I am moving ASAP, or moving into a cabin in the woods.
There are still some things left for me in the city, and some wealth I can
extract from it to secure myself with the means for a better future. I just
don&#x27;t see a very bright future for myself in the city, at least not one aligned
with my ideals.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, of course, I don&#x27;t think most people will leave the &quot;comforts&quot; and
&quot;security&quot; of the cities in exchange for more freedom. Most people in the cities
are so domesticated, that they not only seem unmoved by the trampling of their
liberties, they actually welcome such tyrannical measures.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;&lt;em&gt;“La salvación social se aproxima cuando cada cual confiesa que sólo puede
salvarse a sí mismo. La sociedad se salva cuando sus presuntos salvadores
desesperan.”&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;“Reformar la sociedad por medio de leyes es el sueño del ciudadano incauto y el
preámbulo discreto de toda tiranía. La ley es forma jurídica de toda costumbre o
atropello a la libertad.”&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nicolás Gómez Dávila.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&quot;China criticizes Sweden&#x27;s corona handling&quot;. (in Swedish) —
&lt;a href=&quot;https:&#x2F;&#x2F;www.expressen.se&#x2F;nyheter&#x2F;donald-trump-utlyser-nodlage-i-usa&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.expressen.se&#x2F;nyheter&#x2F;donald-trump-utlyser-nodlage-i-usa&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;worldcoronastatistics.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;worldcoronastatistics.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Simple and Minimal Git Server Setup</title>
		<published>2020-12-31T16:39:56+00:00</published>
		<updated>2020-12-31T16:39:56+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/minimal-git-server/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/minimal-git-server/</id>
		<content type="html">&lt;p&gt;The New Year is just around the corner, but there&#x27;s still a little time to write
one last post before the year ends. This time I want to write about my
experience setting up a git server. I had already set up before a git server
using a free and open source kind of clone of Github called Gitea, but there&#x27;s a
better way to setup a git server, especially if you just want to setup a
personal Git server.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;About a year ago I setup a git server using Gitea&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; server together with a
CI&#x2F;CD system called Drone&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Back then it made sense, because I was working on
some projects with a couple of friends, and I needed easy access for them to be
able to work together with me. However, time went on, we stopped working on
those projects, and I left that git server running for my own needs, i.e. to
store the source of my website and deploy it automatically on each push to
master.&lt;&#x2F;p&gt;
&lt;p&gt;It worked fine all around, but it was too bloated for my tastes, and I didn&#x27;t
really need most of the features that both Gitea and Drone had to offer. The
containerized way of working using Docker containers for the servers themselves,
and for the post-push hooks used, in my opinion, too many resources. And it
turns out I was right.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to get rid of all of that, one, because I didn&#x27;t really needed all of
that; two, because I like minimalism, and try to avoid web interfaces and their
clunky ways of working as much as possible; and three, because I wanted to get
rid of the VPS in which they were hosted, and wanted to have it all on one VPS,
the one where my website is being hosted, among many other things, such as my
email server.&lt;&#x2F;p&gt;
&lt;p&gt;I already knew that there were some light-weight web front-ends for git, such as
cgit&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, or even git&#x27;s own web interface; I didn&#x27;t know what exactly they had
though, so I started digging deeper into git itself, by reading the
documentation, and looking in the internet for tutorials and explanations of how
cgit and similar tools worked.&lt;&#x2F;p&gt;
&lt;p&gt;After learning more about git, and finding myself with more time than usual all
thanks to COVID-19&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and the government, I finally decided to just trying out
setting up my minimal Git server.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;prelude-or-some-things-to-know-before-setting-up-a-git-server&quot;&gt;Prelude, or some things to know before setting up a git server&lt;&#x2F;h2&gt;
&lt;p&gt;Before trying to setup a git server this way, you should know some basic stuff
about how git works. I didn&#x27;t know a lot of these details when I embarked myself
upon this venture, so I ended having to read a good deal of information on the
way git works, which one of the reasons I really enjoyed this. Turns out git is
a much better piece of software than I thought before, and I already had a
really high opinion of it.&lt;&#x2F;p&gt;
&lt;p&gt;First, all of the git hosting solutions out there, Github, Gitlab, Gitea etc.
are using none other that git, and some other like gitolite, as their main
backend.  Every time you push something to, say Github, be it by ssh or http,
git gets called on their server. Github just shows you what git is telling them.&lt;&#x2F;p&gt;
&lt;p&gt;Second, you don&#x27;t really need a web interface to have a git server. The web
interface is just a nice way of showing your repositories to other people. A
computer with ssh access is more than enough, if all you want to do is host your
repositories.&lt;&#x2F;p&gt;
&lt;p&gt;Third, there are, in practice, two types of repositories:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Standard repositories that contain all the information and actual files in the
&lt;code&gt;.git&lt;&#x2F;code&gt; directory, together with a &quot;working directory&quot; at the root, which is the
representation of the state of your projects in the ref you are currently, and
where you actually, well, work on your files by editing them. This are not the
actual files stored by git.&lt;&#x2F;li&gt;
&lt;li&gt;Bare repositories, which forgo the &quot;working directory&quot; and just contain all
the git files and information at the root of the directory. This types of
repositories are the ones meant for the server side of things.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;setting-up-the-git-backend&quot;&gt;Setting up the git backend&lt;&#x2F;h2&gt;
&lt;p&gt;Now that you know a little bit more about how git works (or maybe you already
knew that), it&#x27;s time to set up the actual git server. All you need is a
computer with access to the internet, preferably with a static IP (like a VPS),
and optionally a domain name, just to make things prettier and easier. To guide
myself through this process, I mostly followed the Arch Linux wiki guide on
it&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and the official Git book chapter on Git on the server&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;First thing that you need to do, is setup ssh access. This is pretty easy to do,
you most probably already have it setup, and it is out the scope of this
tutorial, so I am not going to explain how to do it in this post.&lt;&#x2F;p&gt;
&lt;p&gt;Next, you need to make a user specially for git. This is quite important, since
you don&#x27;t want people with access (even just read access) to your repositories
to have access to other parts of your server. For simplicity, we&#x27;ll just call it
git.&lt;&#x2F;p&gt;
&lt;p&gt;Each Linux distro (or Unix-like OS), has its own defaults, and sometimes even
alternate ways to create users. For simplicity&#x27;s sake I decided to use Debian&#x27;s
defaults when creating the git user:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# useradd git
&lt;&#x2F;span&gt;&lt;span&gt;# passwd git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These two commands, at least in Debian Buster, should create a normal user with
a home directory at &lt;code&gt;&#x2F;home&#x2F;git&#x2F;&lt;&#x2F;code&gt; and prompt you for a password for the git user.
Some people like to have the git home directory in a location such as
&lt;code&gt;&#x2F;srv&#x2F;git&#x2F;&lt;&#x2F;code&gt;, but I just decided to go with the defaults for simplicity&#x27;s sake.&lt;&#x2F;p&gt;
&lt;p&gt;Now we need to setup some things for the git user. First we should switch to it:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ su -l git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And once we are the git user, we should make a &lt;code&gt;.ssh&lt;&#x2F;code&gt; folder with a
&lt;code&gt;authorized_keys&lt;&#x2F;code&gt; file, which should contain your public key(s), and also the
keys of any people you plan on having write (push) access to your repositories.
Keep in mind, that any people with push access, will have push access to &lt;strong&gt;all&lt;&#x2F;strong&gt;
of the repositories under the git user.&lt;&#x2F;p&gt;
&lt;p&gt;Now we should think about where we are going to store the git repositories. You
could just store them at the root of the git home directory. However, I decided
to store them in a separate folder, since I also wanted to keep some (mainly
uninteresting) repositories private. So I created two folders &lt;code&gt;private&lt;&#x2F;code&gt;, and
&lt;code&gt;public&lt;&#x2F;code&gt;. Public, as its name implies, is going to be the directory with the
repositories that are going to be shown on the web interface for all the people
to see. I could have also created a separate web interface protected by password
for the &lt;code&gt;private&lt;&#x2F;code&gt; repositories, but the web interface is mainly just for people
on the internet to take a glance at my repositories.&lt;&#x2F;p&gt;
&lt;p&gt;Now for a test, you can create your first repository under the public folder,
and try pushing into it. So we should cd into our &lt;code&gt;public&lt;&#x2F;code&gt; directory (or
whatever directory you plan to store your repositories at) and init a &lt;strong&gt;bare&lt;&#x2F;strong&gt;
repository. By convention bare repository names end with a &lt;code&gt;.git&lt;&#x2F;code&gt;, so it should
look something like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ cd ~&#x2F;public
&lt;&#x2F;span&gt;&lt;span&gt;$ git init --bare my-repo.git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Any time that you want to add a repo to your server, you&#x27;ll basically need to
login to your git user and repeat the steps above. Or, if you already have a
non-empty server, you could clone it this way:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;git clone --bare &amp;lt;path-or-url-to-my-repo&amp;gt; my-repo.git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you can push from your local computer to that directory using ssh this way:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ git remote set-url origin git@your-domain-or-ip:public&#x2F;my-repo.git
&lt;&#x2F;span&gt;&lt;span&gt;$ git push -u origin master
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or clone it, once you have something there:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ git clone git@your-domain-or-ip:public&#x2F;my-repo.git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you have working git server. It&#x27;s that simple! However, right now there&#x27;s
now read-only access for other people to clone your repos. There&#x27;s two ways you
could solve that. You could use git&#x27;s own smart HTTP, or the git daemon. In my
case I didn&#x27;t end up using git&#x27;s smart HTTP, since I used cgit&#x27;s functionality
for that, but if you are interested in any of them, you can check out the
official git book chapter that I mentioned earlier&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Before we go further, though, we need to harden our git user a little bit,
especially if you intend on giving other people push access. Right now, anybody
with push access, basically has ssh access to your git user, since basically
when you are pushing using this method, the only thing that is happening is that
git is ssh&#x27;ing into your server and executing git (the one on your server) in
your server. That&#x27;s a big no-no. For that, we are going to change the standard
login shell of git, to one that will allow git to function properly, but won&#x27;t
allow people to login to an full-fledged interactive shell into your git user
using ssh.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, git provides use with a limited shell for this specific case,
called the git-shell. First, we need to know where it is located:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ which git-shell
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;bin&#x2F;git-shell
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that we know its actual location, we need to change the default shell for
our git user:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# chsh -s &#x2F;usr&#x2F;bin&#x2F;git-shell git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you might think, well, how do I log into the git user to add&#x2F;edit
repositories? Just log into your normal user, and then use &lt;code&gt;su&lt;&#x2F;code&gt; to login with a
shell like sh, bash, or zsh:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ su -s &#x2F;bin&#x2F;bash git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;setting-up-the-web-interface&quot;&gt;Setting up the web interface&lt;&#x2F;h2&gt;
&lt;p&gt;Git provides its own web interface, which, if you want the minimalest of the
minimalest, should be fine. I, however, decided to use cgit&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, since I wanted
a little more flexibility and more room for configuration. It&#x27;s even the
preferred web interface for the kernel.org git repositories.&lt;&#x2F;p&gt;
&lt;p&gt;To use it, we&#x27;ll need not only it, but also a reverse proxy for it to work with
it. My preferred program for that is nginx, I have used it for several years,
and it love it for its ease of use and its performance. You could also use other
software, like Apache, if that&#x27;s what you prefer.&lt;&#x2F;p&gt;
&lt;p&gt;Even though I&#x27;m using Debian on my VPS, I mostly followed the Arch Linux Wiki
article on cgit&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#7&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. If you&#x27;re not yet familiar with the Arch Wiki, you should
definitely check it out. It&#x27;s arguably the best resource on Linux out there.&lt;&#x2F;p&gt;
&lt;p&gt;So basically we need the following packages:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# apt install nginx fcgiwrap cgit
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that, we should go on and configure nginx. I won&#x27;t go into big detail on
how to configure nginx itself, but the configuration file for cgit should be
located here &lt;code&gt;&#x2F;etc&#x2F;nginx&#x2F;sites-available&#x2F;cgit&lt;&#x2F;code&gt; and look something like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;    listen 80;
&lt;&#x2F;span&gt;&lt;span&gt;    listen [::]:80;
&lt;&#x2F;span&gt;&lt;span&gt;    server_name &amp;lt;your-git-domain&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    return 301 https:&#x2F;&#x2F;$host$request_uri;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;    listen 443 ssl;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    server_name &amp;lt;your-git-domain&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    ssl_certificate &amp;lt;your-ssl-cert-path&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    ssl_certificate_key &amp;lt;your-ssl-cert-key-path&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    root                  &#x2F;usr&#x2F;share&#x2F;cgit;
&lt;&#x2F;span&gt;&lt;span&gt;    try_files             $uri @cgit;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    location @cgit {
&lt;&#x2F;span&gt;&lt;span&gt;                include             fastcgi_params;
&lt;&#x2F;span&gt;&lt;span&gt;                fastcgi_param       SCRIPT_FILENAME &#x2F;usr&#x2F;lib&#x2F;cgit&#x2F;cgit.cgi;
&lt;&#x2F;span&gt;&lt;span&gt;                fastcgi_param       PATH_INFO       $uri;
&lt;&#x2F;span&gt;&lt;span&gt;                fastcgi_param       QUERY_STRING    $args;
&lt;&#x2F;span&gt;&lt;span&gt;                fastcgi_param       HTTP_HOST       $server_name;
&lt;&#x2F;span&gt;&lt;span&gt;                fastcgi_pass        unix:&#x2F;run&#x2F;fcgiwrap.socket;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This configuration assumes that you have setup an SSL certificate. You can
configure it just use plain HTTP, but I really recommend you get an SSL
certificate.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have nginx configured we should start and enable both nginx and
fcgiwrap.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, you should be able to see cgit by going to the domain or url that
you pointed at in the nginx config. However, it probably won&#x27;t be showing you
your repositories just yet, and that&#x27;s because we need configure cgit, in part
so that we can tell it where to look for our repos.&lt;&#x2F;p&gt;
&lt;p&gt;I won&#x27;t go into much detail on how to configure cgit, but I&#x27;ll show you my
configuration file, so you have an idea of how to configure yours. This file
should be located at &lt;code&gt;&#x2F;etc&#x2F;cgitrc&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;#
&lt;&#x2F;span&gt;&lt;span&gt;# cgit config
&lt;&#x2F;span&gt;&lt;span&gt;# see cgitrc(5) for details
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;css=&#x2F;cgit.css
&lt;&#x2F;span&gt;&lt;span&gt;logo=&#x2F;cgit.png
&lt;&#x2F;span&gt;&lt;span&gt;virtual-root=&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;max-repodesc-length=100
&lt;&#x2F;span&gt;&lt;span&gt;repository-sort=age
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;root-title=Yaroslav&amp;#39;s git repositories
&lt;&#x2F;span&gt;&lt;span&gt;root-desc=Public repos for some of my projects, and mirrors of other projects.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# Possible readme files for about page
&lt;&#x2F;span&gt;&lt;span&gt;readme=:README.md
&lt;&#x2F;span&gt;&lt;span&gt;readme=:README.txt
&lt;&#x2F;span&gt;&lt;span&gt;readme=:README.rst
&lt;&#x2F;span&gt;&lt;span&gt;readme=:README
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# Syntax highlighting
&lt;&#x2F;span&gt;&lt;span&gt;source-filter=&#x2F;usr&#x2F;local&#x2F;lib&#x2F;cgit&#x2F;filters&#x2F;syntax-highlighting.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# About page rendering script
&lt;&#x2F;span&gt;&lt;span&gt;about-filter=&#x2F;usr&#x2F;local&#x2F;lib&#x2F;cgit&#x2F;filters&#x2F;about-formatting.sh
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# Some common mimetypes for serving files raw
&lt;&#x2F;span&gt;&lt;span&gt;mimetype.gif=image&#x2F;gif
&lt;&#x2F;span&gt;&lt;span&gt;mimetype.html=text&#x2F;html
&lt;&#x2F;span&gt;&lt;span&gt;mimetype.jpg=image&#x2F;jpeg
&lt;&#x2F;span&gt;&lt;span&gt;mimetype.jpeg=image&#x2F;jpeg
&lt;&#x2F;span&gt;&lt;span&gt;mimetype.pdf=application&#x2F;pdf
&lt;&#x2F;span&gt;&lt;span&gt;mimetype.png=image&#x2F;png
&lt;&#x2F;span&gt;&lt;span&gt;mimetype.svg=image&#x2F;svg+xml
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# Set of snapshot formats for people to download
&lt;&#x2F;span&gt;&lt;span&gt;snapshots=tar.gz zip
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# Git configuration
&lt;&#x2F;span&gt;&lt;span&gt;enable-http-clone=1
&lt;&#x2F;span&gt;&lt;span&gt;enable-commit-graph=1
&lt;&#x2F;span&gt;&lt;span&gt;remove-suffix=1
&lt;&#x2F;span&gt;&lt;span&gt;section-from-path=1
&lt;&#x2F;span&gt;&lt;span&gt;scan-path=&#x2F;home&#x2F;git&#x2F;public
&lt;&#x2F;span&gt;&lt;span&gt;clone-prefix=https:&#x2F;&#x2F;git.yaroslavps.com git:&#x2F;&#x2F;git.yaroslavps.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The most important bits here are:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;virtual-root=&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;enable-http-clone=1
&lt;&#x2F;span&gt;&lt;span&gt;scan-path=&#x2F;home&#x2F;git&#x2F;public
&lt;&#x2F;span&gt;&lt;span&gt;clone-prefix=https:&#x2F;&#x2F;git.yaroslavps.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can read more about cgit&#x27;s configuration in the Arch Wiki article I
mentioned earlier&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#8&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. I&#x27;ll just say, that you should keep in mind that the
order of the configuration variables is important. If something is not working
as it should, its probably because you put some variable before another one, and
their order should be changed. This gave a big headache when I was trying to
configure cgit for myself.&lt;&#x2F;p&gt;
&lt;p&gt;One last thing worth mentioning, regarding cgit, is that you can configure each
repo for cgit by adding a &lt;code&gt;cgitrc&lt;&#x2F;code&gt; file inside the bare repository in your
server. You can then add some more information about it like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;owner=Yaroslav de la Peña Smirnov &amp;lt;email@host.tld&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;desc=Personal site and blog.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For more information, read cgitrc&#x27;s manual:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ man 5 cgitrc
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This is one possible way of having your own hosting solution for git
repositories, in a very minimal way. Since the cgit frontend is not running
constantly, it&#x27;s written in C, and is very minimal, it barely consumes any
resources. This is also a great way to be more independent of centralized,
proprietary services like GitHub. Of course, services like those are always
great for visibility, but you could always just have mirror of your open source
projects on them that points to your personal server.&lt;&#x2F;p&gt;
&lt;p&gt;There many other great things that you can do with a setup like this, like
setting up git hooks, without having to set up a complex and complicated CI&#x2F;CD
system, for simple tasks, like in my case, pushing, generating and deploying my
site on each push to master. For an example of a post-receive you can checkout
mine here:
&lt;a href=&quot;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;yaroslavps.com&#x2F;tree&#x2F;post-receive&quot;&gt;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;yaroslavps.com&#x2F;tree&#x2F;post-receive&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For a little more information on git, I recommend you to read the following
manual pages:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ man git
&lt;&#x2F;span&gt;&lt;span&gt;$ man git-init
&lt;&#x2F;span&gt;&lt;span&gt;$ man git-clone
&lt;&#x2F;span&gt;&lt;span&gt;$ man git-config
&lt;&#x2F;span&gt;&lt;span&gt;$ man githooks
&lt;&#x2F;span&gt;&lt;span&gt;$ man git-send-email
&lt;&#x2F;span&gt;&lt;span&gt;$ man git-format-patch
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The last are especially useful if you want to know how to collaborate with other
people on other projects, or want other people to collaborate on yours, without
having to resort to the centralized way of doing things of GitHub and similar
sites. Git is especially well suited for collaborating through email, which is
in and of itself a decentralized service. There&#x27;s a guide on collaborating
through email using git&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#8&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, written by the great Drew DeVault, which is, in my
opinion, one of the best FOSS programmers out there. I recommend also to check
out his blog&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#9&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, which I must say is much more interesting than mine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-little-unrelated-note&quot;&gt;A little unrelated note&lt;&#x2F;h2&gt;
&lt;p&gt;As I write this post, this strange year is (finally) coming to an end. It wasn&#x27;t
a completely terrible year per se, but it did present us with a lot of nasty
surprises. I have quite a lot of personal plans for this coming 2021, some of
which involve this site. Some of them I&#x27;ll keep a secret for now, but most
importantly I want to diversify my writing a little bit more. I kind of already
did that this year, with my &quot;recipe book&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#10&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but I also want to start writing
about some other things on my weblog. So far it&#x27;s been mostly about software
development and computer-related stuff, but there are many other things not
related to that on my mind, which I&#x27;d like to write about.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s to a New Year, that&#x27;s not as Orwellian as this one, and may you
accomplish as much as you set yourself to accomplish.&lt;&#x2F;p&gt;
&lt;p&gt;Happy New Year and Merry Christmas&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#11&quot;&gt;11&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; to all!&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gitea.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;gitea.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.drone.io&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.drone.io&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git.zx2c4.com&#x2F;cgit&#x2F;about&#x2F;&quot;&gt;https:&#x2F;&#x2F;git.zx2c4.com&#x2F;cgit&#x2F;about&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;I&#x27;ll write a little bit about my experience with the corona, and my
thoughts on it next year.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;Git_server&quot;&gt;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;Git_server&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;&lt;&#x2F;div&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Git-on-the-Server-Getting-Git-on-a-Server&quot;&gt;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Git-on-the-Server-Getting-Git-on-a-Server&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;7&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;Cgit&quot;&gt;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;Cgit&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;8&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git-send-email.io&#x2F;&quot;&gt;https:&#x2F;&#x2F;git-send-email.io&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;9&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;drewdevault.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;drewdevault.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;10&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;food&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;food&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;11&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;11&lt;&#x2F;sup&gt;
&lt;p&gt;I know, a little bit late for Catholic or Protestant folks out there. But
just in time for (Russian) Orthodox Christmas ;)&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>A little fun with Zoom</title>
		<published>2020-12-20T19:49:00+00:00</published>
		<updated>2020-12-20T19:49:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/zoom-trolling/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/zoom-trolling/</id>
		<content type="html">&lt;p&gt;Since the beginning of the Orwellian nightmare that befell upon us this year,
many of us have been forced to not only fundamentally change the way that we go
about our lives and interact with other people, but also to use platforms for
video communications that not only are proprietary, but are also of very dubious
origin and quality. Well, either that, or fail academically (for those still in
university, like myself), or professionally (for those being forced to use this
software at work). That, however, doesn&#x27;t mean that you cannot make use of the
situation and have a little fun.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Disclaimer: I am not responsible for any consequences that may result of your
use of this trick. Use it at your own discretion.&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In trying to find a way to share my screen on Zoom in Wayland, I thought that it
might not hurt if I had a little fun in one of my &quot;Zoom classes&quot;. After all, I
was forced to install this Chinese spyware in my computer, the least I could do
is have fun with it. As is known, many programs lack the ability to capture or
share the screen in Wayland. I am required to share my screen from time on my
remote classes, so I was thinking of a way I could do just that.&lt;&#x2F;p&gt;
&lt;p&gt;One day, a thought came to my mind. In Linux systems (as in most Unix-like
systems) everything is a file. Therefore, webcams are also a file
(&lt;code&gt;&#x2F;dev&#x2F;video*&lt;&#x2F;code&gt;). So in theory, I should be able to capture my screen with the
screen capture software I normally use, and somehow redirect it to a &quot;fake&quot;
webcam, and from there use that fake webcam in any videoconferencing software
(e.g. Zoom) as I would my normal real webcam.&lt;&#x2F;p&gt;
&lt;p&gt;As it is most of the time, some people had already invented the solution to my
problem, and the software I was looking for, came in the form a kernel module
called &lt;code&gt;v4l2loopback&lt;&#x2F;code&gt;. This genius piece of software does precisely what I was
thinking of, it creates a fake webcam in &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt;. However, it was only the first
part of the equation, the second part is the software that captures the screen
itself and redirects it to the fake webcam. It doesn&#x27;t even have to be your
screen, it could be any video stream. After finding the solution, I decided to
kill two birds with one stone, and test it by being a troll in one of my
classes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;some-instructions&quot;&gt;Some instructions&lt;&#x2F;h2&gt;
&lt;p&gt;I use Artix Linux (i.e. Arch Linux sans Systemd), so the instructions that I am
writing here apply for that distro. However, I am pretty sure you reproduce
these instructions with small modifications in any other Linux distribution.&lt;&#x2F;p&gt;
&lt;p&gt;First we&#x27;ll need some packages. The packages that are or might be of use are the
following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;v4l2loopback — the kernel module that will create the fake webcam.&lt;&#x2F;li&gt;
&lt;li&gt;ffmpeg — (optional&#x2F;recommended) if you haven&#x27;t used ffmpeg yet, I recommend
that you install it even if you aren&#x27;t going to use it for the purposes of this
post. It is a utility for working with video and audio. In this case, it will
allow us to redirect video files into the fake webcam, or, if you are using X,
capture your screen and redirect it to the cam.&lt;&#x2F;li&gt;
&lt;li&gt;wf-recorder — (optional&#x2F;wayland;wlroots) this is the defacto program for
screen capture in Wayland compositors that are based of off
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;swaywm&#x2F;wlroots&quot;&gt;wlroots&lt;&#x2F;a&gt;. In my case, I use
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;swaywm&#x2F;sway&quot;&gt;Sway&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So in Artix&#x2F;Arch you would install them like so:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# pacman -Sy v4l2loopback-dkms ffmpeg wf-recorder
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After installation we&#x27;ll need to rebuild the boot image:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# mkinitcpio -p &amp;lt;your-kernel&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Where &lt;code&gt;&amp;lt;your-kernel&amp;gt;&lt;&#x2F;code&gt; is the name of your linux kernel image, e.g. &lt;code&gt;linux&lt;&#x2F;code&gt;,
&lt;code&gt;linux-lts&lt;&#x2F;code&gt;, &lt;code&gt;linux-zen&lt;&#x2F;code&gt;, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Before using the module we&#x27;ll, of course, need to reboot. However, I added a
little line to my &lt;code&gt;&#x2F;etc&#x2F;rc.local&lt;&#x2F;code&gt; file, so that the fake webcam would be added
right upon system boot:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;modprobe v4l2loopback card_label=&amp;quot;Screen share&amp;quot; exclusive_caps=1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you don&#x27;t want it to appear after every boot, you can just execute that
command as root on your terminal any time you need it. The fake webcam will
disappear after a reboot. You can also remove them yourself, and add different
loopback devices, for that, consult the documentation of the v4l2loopback
project.&lt;&#x2F;p&gt;
&lt;p&gt;Now is when the fun can start. For the first example, showing video in the
webcam, by using ffmpeg:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ ffmpeg -i &amp;lt;your-video-file&amp;gt; -f v4l2 &#x2F;dev&#x2F;video&amp;lt;X&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The fake webcam should be the last video device if you already had your real
webcam(s) connected. So if you already had &lt;code&gt;&#x2F;dev&#x2F;video0&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;dev&#x2F;video1&lt;&#x2F;code&gt;, then
the loopback webcam should be &lt;code&gt;&#x2F;dev&#x2F;video2&lt;&#x2F;code&gt;, unless you specified it to be
something else when loading the v4l2loopback module.&lt;&#x2F;p&gt;
&lt;p&gt;Second example, show your X11 desktop in your webcam, using ffmpeg:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ ffmpeg -f x11grab -i :0.0+0,0 -vcodec rawvideo -pix_fmt yuv420p -f v4l2 &#x2F;dev&#x2F;video&amp;lt;X&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The last example, and the one that applies to my case, showing the desktop of my
(wlroots-based) Wayland compositor:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ wf-recorder -o &amp;lt;display-name&amp;gt; -x yuv420p -c rawvideo -m v4l2 -f &#x2F;dev&#x2F;video&amp;lt;X&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I also have a script in my dotfiles for easy screen recording (and now also
sharing) under Sway using bemenu (dmenu for Wayland)
&lt;a href=&quot;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;configs&#x2F;swayrice&#x2F;tree&#x2F;dotfiles&#x2F;.local&#x2F;bin&#x2F;swayrecord&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-results&quot;&gt;The results&lt;&#x2F;h2&gt;
&lt;p&gt;If you followed the instructions up to this point, then: congratulations! Now
you can do stuff like this:&lt;&#x2F;p&gt;
&lt;video loop muted autoplay&gt;
&lt;source src=&quot;zoom-trolling.mp4&quot;&gt;
&lt;&#x2F;video&gt;
&lt;p&gt;Well, of course, you can be better than me and actually use it for something
useful, like sharing your presentation slideshow with your peers. But where&#x27;s
the fun in that?&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>The indentation Red Pill</title>
		<published>2020-10-11T13:20:52+00:00</published>
		<updated>2020-10-11T13:20:52+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/the-indentation-red-pill/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/the-indentation-red-pill/</id>
		<content type="html">&lt;p&gt;For the last several years I had been using spaces for indentation. I had
decided to settle upon that method of indentation without much thought, just
based on what I observed was the most popular choice. Well, that, and also the
fact that I was writing mostly Python back then, which greatly influenced my
decision. Recently however, I decided to switch to using tabs - at least for my
own projects - and I am going to layout here the reasons why I concluded tabs to
be The Superior indentation method.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;I must first mention that the thing that made me question why I used the method
of indentation that I used was a neat language that I have been recently
studying - Go. One of the virtues (albeit with its set of downsides) of the Go
language, is that it is quite opinionated, and one of this areas is code
formatting, which by definition includes indentation. And the Go way of
indenting is: tabs.&lt;&#x2F;p&gt;
&lt;p&gt;Now mind you, the way they did it allows you to continue using your preferred
indentation method while at the same outputting correctly formatted code as per
the standard with a neat little tool called &lt;code&gt;gofmt&lt;&#x2F;code&gt;. But that is another topic
for another day.&lt;&#x2F;p&gt;
&lt;p&gt;Finding out that tabs is the standard way of writing (or at least publishing)
code in Go surprised me a little bit. After all, if we judge by the amount of
projects in public repositories that use spaces, vs those that use tabs for
indentation, then spaces is the clear winner here. I was still curious, though,
as to why tabs was chosen as the standard for indentation for Go, and so I began
a quest to find an answer on the Internet.&lt;&#x2F;p&gt;
&lt;p&gt;Alas, I did not find any concrete answer on the Internet from any of the people
who worked on or designed the Go language. I did find myself reading a lot of
arguments for and against each of the indentation methods on the Internet, which
made me actually evaluate whether my choice of indentation was the better one.
After all, this is one the of the oldest holy wars among programmers, that might
even predate the Internet (or at least the Web).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;spaces&quot;&gt;Spaces&lt;&#x2F;h2&gt;
&lt;p&gt;The main arguments for and against that I could think of, and that I gathered
from other people on the Internet are as follows:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pros&quot;&gt;Pros&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;More consistency in how the code is presented in different text editors and
environments. Mind you, after some thinking, I no longer believe this to be
really a pro, and could be even considered to be a con for reasons I&#x27;ll
mention later in this text.&lt;&#x2F;li&gt;
&lt;li&gt;More people and projects use this. Not a very strong argument, considering
that it is an &lt;em&gt;argumentum ad populum&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Because of different settings on different editors, alignment with tabs might
look off in some of those environments affecting readability. Now this is the
strongest pro that I could think of, however, it applies more &lt;em&gt;alignment&lt;&#x2F;em&gt;,
rather than &lt;em&gt;indentation&lt;&#x2F;em&gt;. More on that later.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;cons&quot;&gt;Cons&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Spaces - unless you or your team are masochists using one-space indentation -
use more disk space than tabs. If you are using 4 spaces for indentation,
arguably the most commonly used amount, then you are using at least 3 more
bytes per line than if you were using tabs.&lt;&#x2F;li&gt;
&lt;li&gt;Spaces are meant to be used as, surprise, surprise, spaces between words. Tabs
are a special character than give precisely the needed context for indentation
and tabulation.&lt;&#x2F;li&gt;
&lt;li&gt;If you are working with other people, you are basically forcing people to an
indentation setting that not only they might not prefer, but could actually
hurt their productivity.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;tabs&quot;&gt;Tabs&lt;&#x2F;h2&gt;
&lt;p&gt;Now I&#x27;ll list the main arguments for and against using tabs. This list mostly
mirrors the one on spaces, just from another point of view:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pros-1&quot;&gt;Pros&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Freedom of choice. Using tabs means that anybody working on the same project
can choose how they like the code to look on their computers, without actually
changing how the code is formatted. This goes against the argument for spaces,
that positions spaces as being more consistent. I believe, though, that this
argument better holds for reasons I&#x27;ll mention below.&lt;&#x2F;li&gt;
&lt;li&gt;Tabs use up less disk space than spaces do (get it, because they are called
spaces, okay, maybe not), as I previously mentioned.&lt;&#x2F;li&gt;
&lt;li&gt;Context. Tabs were made for this purpose, all the way back to typewriters&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;,
enough said.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;cons-1&quot;&gt;Cons&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;They are not displayed consistently. Once more, this argument doesn&#x27;t really
hold water for reasons I&#x27;ll mention later.&lt;&#x2F;li&gt;
&lt;li&gt;Most people and projects use spaces for indentation, which means tabs are not
the preferable indentation method. Once more, &lt;em&gt;argumentum ad populum&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Alignment might look off in different settings, but once again, alignment is
not indentation, and this can be worked.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;head-to-head&quot;&gt;Head-to-head&lt;&#x2F;h2&gt;
&lt;p&gt;It might appear at first that the arguments for and against each of the
specified methods of indentation are pretty much tied. However, as I have
already been mentioning, the arguments for tabs ending up being more compelling
than the arguments for spaces. Let&#x27;s consider the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consistency&lt;&#x2F;strong&gt; - The pro-spaces people seem to suggest that imposing a set
number of spaces as the standard for indentation achieves consistency in the
code base. This, in my opinion, is very misleading, since the only consistency
that you are achieving is how the code looks on the machine of everybody on
the team, thus imposing the tastes of a person or group of people to everybody
else, without actually improving productivity, potentially even negatively
affecting productivity for some people. Take into account, that what might be
readable for you (e.g., 4 spaces), might not be readable for other people,
which might include visually impaired people. Ah, but some people here will be
quick to point out that some editors, or code hosting solutions will just
refuse to display tabs in a consistent or proper way. To which I reply, why
use such incompetent software, when literally most modern text editors and
IDEs have the ability to configure the amount of spaces a tab takes up on the
screen?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Alignment&lt;&#x2F;strong&gt; - Once more, alignment is not indentation, although it does have
to do with it. I do have to agree, however, that spaces are in most cases
better suited for alignment, since what was aligned to look good at a tab
width of, say, 4, might not look good at a tab width setting of 8. But, who
said that you can&#x27;t use spaces for alignment, while using tabs for
indentation? Most competent text editors and IDEs should offer a setting for
&#x27;smart tabs&#x27;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Most projects&#x2F;people use spaces&lt;&#x2F;strong&gt; - As already mentioned, this is a
fallacious argument. Just because most people do or believe something, that
doesn&#x27;t make it right or correct. It is worth mentioning though, that it is
easier to collaborate with people when there are some standard practices in
place. That said, this does not mean that you shouldn&#x27;t used a better set of
practices in your own projects, while also using some other standards while
collaborating on others, especially taking into that most competent text
editors are capable of using the indentation in use for said projects, instead
of the user-set indentation. Not to mention that many languages nowadays
provide tooling for formatting the code to the agreed standards.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;After thinking about it for awhile, I came to the conclusion that tabs are
indeed objectively superior to spaces mostly because of freedom, more
specifically the freedom to choose the indentation spacing that is most friendly
to your eyes.&lt;&#x2F;p&gt;
&lt;p&gt;Imposing a defined number of spaces on indentation, seems akin to me to
mandating that people in a team use a specific color scheme for their editors,
just because someone believes that &quot;colorA on colorB is more readable than
colorC on colorD, and besides, there should be consistency on the codebase&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;So I decided that from this day forth, I will be using tabs in all of my
personal projects, and those projects in which I have a say. Yes, even when
programming in languages that suggest otherwise (I&#x27;m looking at you, Rust).&lt;&#x2F;p&gt;
&lt;p&gt;That said, I do respect the choices made by other people, and since I have a
non-retarded text editor (i.e., vim) that can automatically change the
indentation style based on what is already being used on a per-file basis, I can
actually continue to contribute code to projects where those choices might
differ from mine.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;patents.google.com&#x2F;patent&#x2F;US908221&quot;&gt;Tabulating mechanism for type-writing machines.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Goodbye OpenVPN, hello Wireguard</title>
		<published>2020-06-06T02:13:28+00:00</published>
		<updated>2021-03-28T21:23:16+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/wireguard-vpn/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/wireguard-vpn/</id>
		<content type="html">&lt;p&gt;I had been using OpenVPN for quite some time for my internet privacy purposes.
However, I recently decided to switch to Wireguard. I am going to layout the
reason why I chose to do it, and how I setup the Wireguard VPN for my purposes.
I had been meaning to write about this for some time. Unfortunately, I have been
quite busy finishing my last year of university.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;I had heard about this new VPN thing-y called Wireguard last year and how it is
supposed to be so much better than other VPN technologies such as IPsec and
OpenVPN. It sounded nice to me and all, but it still wasn&#x27;t considered stable
back then, and I really didn&#x27;t feel like switching when I had a setup that &quot;just
works™&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;But then, something happened. My then hosting provider decided to cancel their
VPS hosting plans, so I had to migrate everything that I had on my VPS to a new
hosting provider, which included this site and my VPN. Also by this time, the
stable release of Wireguard had been release, and the kernel module added to
upstream. When I was in the process of migrating to my new VPS, I actually
started to setup OpenVPN first, but some things had changed since the last time
I had setup OpenVPN, and I didn&#x27;t really want to deal with OpenVPN at this
point. That&#x27;s when I remembered about Wireguard. Good timing, if I do say so
myself.&lt;&#x2F;p&gt;
&lt;p&gt;I have been using Wireguard for over a month now, and I have to say, I am really
happy with it. It really is better than OpenVPN. The main advantages that
Wireguard has over OpenVPN for me are the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It is so much easier to setup. No need to mess around with certificates.&lt;&#x2F;li&gt;
&lt;li&gt;Adding new clients or peers is also much easier and straightforward.&lt;&#x2F;li&gt;
&lt;li&gt;Latency and speed are slightly better than OpenVPN, especially latency. It
might not be such a big difference, but I no longer feel the need to turn off
my VPN when videoconferencing.&lt;&#x2F;li&gt;
&lt;li&gt;It brings up the network interface(s) much faster than OpenVPN.&lt;&#x2F;li&gt;
&lt;li&gt;It consumes less resources.&lt;&#x2F;li&gt;
&lt;li&gt;I had to disconnect and manually reconnect OpenVPN every time I resumed my
computer from sleep or when I changed networks. With Wireguard, not anymore.
It has a built-in roaming feature, so it doesn&#x27;t matter if I suspend my
computer, after waking up it &quot;keeps&quot; the connection for me, the same when I,
for example, disconnect from WiFi and connect to ethernet, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If these advantages haven&#x27;t convinced you yet, I don&#x27;t know what will.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;set-up-instructions&quot;&gt;Set up instructions&lt;&#x2F;h2&gt;
&lt;p&gt;There are some things that are worth keeping in mind while setting up Wireguard.
One of them is that unlike other VPN protocols, like OpenVPN, there is no server
and client per se. There are just peers. Of course, that doesn&#x27;t mean that you
cannot use Wireguard like you would use OpenVPN, quite the contrary. It just
means there is more flexibility and that you need to configure the peer that
you&#x27;re going to use as a server, such that it tunnels all the internet traffic
it receives from the other peers and reroutes it.&lt;&#x2F;p&gt;
&lt;p&gt;Before setting up Wireguard, you&#x27;ll need to install it on each peer. Check out
this link on how to install Wireguard on your system:
&lt;a href=&quot;https:&#x2F;&#x2F;www.wireguard.com&#x2F;install&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.wireguard.com&#x2F;install&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;server-configuration&quot;&gt;Server configuration&lt;&#x2F;h3&gt;
&lt;p&gt;Before setting up Wireguard, you might want to setup a firewall such as &lt;code&gt;ufw&lt;&#x2F;code&gt;.
After installing Wireguard and setting up your firewall, it&#x27;s time to create a
new profile for your connection.&lt;&#x2F;p&gt;
&lt;p&gt;First, as root, change to the &lt;code&gt;&#x2F;etc&#x2F;wireguard&#x2F;&lt;&#x2F;code&gt; directory.&lt;&#x2F;p&gt;
&lt;p&gt;You&#x27;ll need to create a private key, and from that private key you should get
the public key for your clients.&lt;&#x2F;p&gt;
&lt;p&gt;Generating a private key is as simple as this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;wg&lt;&#x2F;span&gt;&lt;span&gt; genkey
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then you&#x27;ll need to create the profile, for that create file wg0.conf with the
following contents:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;[Interface]
&lt;&#x2F;span&gt;&lt;span&gt;Address = 10.0.0.1&#x2F;24
&lt;&#x2F;span&gt;&lt;span&gt;Address = fd86:ea04:1115::1&#x2F;64
&lt;&#x2F;span&gt;&lt;span&gt;PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE
&lt;&#x2F;span&gt;&lt;span&gt;PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE
&lt;&#x2F;span&gt;&lt;span&gt;ListenPort = 51820
&lt;&#x2F;span&gt;&lt;span&gt;PrivateKey = &amp;lt;server private key&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You should put the private key that you generated before in the wg0.conf file in
the &quot;PrivateKey&quot; field.&lt;&#x2F;p&gt;
&lt;p&gt;Now is a good time to get the public key. It would be convenient to have it
saved in a file so that you can easily retrieve in the future when you need to
add new peers:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;server private key&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;wg&lt;&#x2F;span&gt;&lt;span&gt; pubkey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; wg0.pubkey
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you already have setup a firewall on your server, don&#x27;t forget to allow
connections on the port being used by Wireguard. For example, for ufw you would
run the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ufw&lt;&#x2F;span&gt;&lt;span&gt; allow 51820&#x2F;udp
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you can bring up your Wireguard tunnel by using this command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;wg-quick&lt;&#x2F;span&gt;&lt;span&gt; up wg0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can make sure that it&#x27;s running by entering:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;wg&lt;&#x2F;span&gt;&lt;span&gt; show
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, if you want to bring up your Wireguard VPN tunnel every time your
server restarts, you might prefer to manage your connection with systemd. First
we have to bring down the tunnel we just brought up:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;wg-quick&lt;&#x2F;span&gt;&lt;span&gt; down wg0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And now we can enable and start our respective systemd service:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span&gt; enable wg-quick@wg0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span&gt; start wg-quick@wg0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since in this configuration we want to be able to forward all of the peers&#x27;
traffic through the VPS, we need to enable packet forwarding in the kernel by
adding or uncommenting the following lines to &lt;code&gt;&#x2F;etc&#x2F;sysctl.conf&lt;&#x2F;code&gt;, or creating a
new file in &lt;code&gt;&#x2F;etc&#x2F;sysctl.d&#x2F;&lt;&#x2F;code&gt; with these lines:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;net.ipv4.ip_forward=1
&lt;&#x2F;span&gt;&lt;span&gt;net.ipv6.conf.all.forwarding=1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After adding them, to immediately load the config we run&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;sysctl&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; --system
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;client-configuration&quot;&gt;Client configuration&lt;&#x2F;h3&gt;
&lt;p&gt;The configuration for the client side of things is pretty similar to the server
side of things, since after all, to Wireguard there is no server or client.&lt;&#x2F;p&gt;
&lt;p&gt;You can save your Wireguard profile in the same directory as in the server, i.e.
&lt;code&gt;&#x2F;etc&#x2F;wireguard&#x2F;&lt;&#x2F;code&gt;. However, I prefer to keep it inside my home directory (e.g.
&lt;code&gt;~&#x2F;docs&#x2F;wireguard&lt;&#x2F;code&gt;), since I want to manage my VPN connection on my client
machine by using NetworkManager. The client profile should look something like
this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;[Interface]
&lt;&#x2F;span&gt;&lt;span&gt;Address = 10.0.0.2&#x2F;24
&lt;&#x2F;span&gt;&lt;span&gt;PrivateKey = &amp;lt;client private key&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;ListenPort = 51820
&lt;&#x2F;span&gt;&lt;span&gt;DNS = 1.1.1.1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[Peer]
&lt;&#x2F;span&gt;&lt;span&gt;PublicKey = &amp;lt;server public key&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;AllowedIPs = 0.0.0.0&#x2F;0
&lt;&#x2F;span&gt;&lt;span&gt;Endpoint = &amp;lt;server IP&amp;gt;:51820
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Back on the server, append an entry for your client device to the end of the
wg.conf file:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;[Peer]
&lt;&#x2F;span&gt;&lt;span&gt;PublicKey = &amp;lt;client public key&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;AllowedIPs = 10.0.0.2&#x2F;32
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you have to restart the service on the server, for example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span&gt; restart wg-quick@wg0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that you can connect your client machine to the server using the Wireguard
tunnel. You can use the &lt;code&gt;wg-quick up wg0&lt;&#x2F;code&gt; command, but as I mentioned before, I
want to manage the VPN with NetworkManager. For that you&#x27;ll first need to import
the profile into NetworkManager:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nmcli&lt;&#x2F;span&gt;&lt;span&gt; connection import type wireguard file &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PROFILE_LOCATION
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After importing the profile you can bring up the tunnel by issuing the following
command (note: the connection will be called &quot;wg0&quot; if the filename of your
profile was &quot;wg0.conf&quot;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nmcli&lt;&#x2F;span&gt;&lt;span&gt; connection up wg0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can bring it down by issuing the following command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;nmcli&lt;&#x2F;span&gt;&lt;span&gt; connection down wg0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I should say that by default NetworkManager will connect to the VPN each that
you reboot. If you want to change this or any other setting check &lt;code&gt;man nmcli&lt;&#x2F;code&gt;
and &lt;code&gt;man nm-settings&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setting-it-up-on-your-phone-or-other-devices&quot;&gt;Setting it up on your phone or other devices&lt;&#x2F;h3&gt;
&lt;p&gt;If you want to connect to your VPN server from other devices, you just have to
basically make a new profile the same way you did in the previous section. Just
keep in mind that you need to generate a new private&#x2F;public key pair for each
new profile, and that each peer (including your server) such have a different IP
address assigned.&lt;&#x2F;p&gt;
&lt;p&gt;If you have an Android phone, after making the profile for your phone and adding
the appropriate entry in your server&#x27;s config file, you can then copy that file
to your phone and import it in the Wireguard app. Or even better, you can make
a QR code of the profile file, and then import that file using the QR code
function of the Wireguard app.&lt;&#x2F;p&gt;
&lt;p&gt;To generate a QR code of the profile app you can use the command line program
&lt;code&gt;qrencode&lt;&#x2F;code&gt;, like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;qrencode&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -t&lt;&#x2F;span&gt;&lt;span&gt; ansiutf8&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -r &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PROFILE_LOCATION
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that a QR code should appear on your terminal window. It should look
similar to this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;wireguard-vpn&#x2F;qrexample.png&quot; alt=&quot;QR code example&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;&#x2F;h2&gt;
&lt;p&gt;In this post I described how to setup a Wireguard VPN in which one of the peers
works as the server, redirecting all internet traffic from all of the other
peers through itself. While this is the configuration that most suits my needs,
and probably also of most people that see a VPN as a privacy tool first and
foremost, there are other possible configurations of Wireguard.&lt;&#x2F;p&gt;
&lt;p&gt;You should take a look at the &lt;a href=&quot;https:&#x2F;&#x2F;www.wireguard.com&quot;&gt;official Wireguard site&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Website refactor</title>
		<published>2020-05-07T12:31:16+00:00</published>
		<updated>2020-12-10T22:02:02+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/website-refactor/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/website-refactor/</id>
		<content type="html">&lt;p&gt;A couple of months ago I had decided to completely refactor my website and blog.
Finally I have done so, and even though I think it still needs some work, I am
much more happy with it now than before.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;It&#x27;s been more than a week since I&#x27;ve actually migrated my site to the new
format, but I haven&#x27;t had the time to write about it, being all busy with my
thesis work. Actually, I am writing this while I am waiting for some stuff that
I need for my work to compile.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-old-site&quot;&gt;The old site&lt;&#x2F;h2&gt;
&lt;p&gt;One thing that I didn&#x27;t quite like about it, was that it was pretty bloated
having used Django just for a little personal weblog site. It&#x27;s not like there
is something inherently wrong about using Django or something similar. I really
liked to use it at the beginning since it is a pretty useful and comfortable
framework to use, especially when you are a beginner. The problem is that it
comes with a lot of bells and whistles that you most probably don&#x27;t need,
especially if you&#x27;re just making a small personal weblog. But this wasn&#x27;t even
the main reason I decided to completely redo it.&lt;&#x2F;p&gt;
&lt;p&gt;However, the main reason why I decided to completely refactor my site, was that
over the last couple of years since I first started my site, my overall workflow
and the way I use computers had fundamentally changed, and I now found it quite
uncomfortable to publish to and manage my site. I just find very jarring to use
web interfaces for &quot;productivity&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;The way I would publish posts and do most of the &quot;managing&quot; of my weblog, was
through the &quot;admin&quot; panel that I would access with my browser through a special
URL. As I said, web interfaces are not my cup of tea, and that includes typing
and redacting articles or posts. I have a nice and comfy setup of neovim which I
actually use to type and redact almost all of the text that I have to write on
my computer. And so I wanted to type my articles on vim, and preferably not even
have to leave the comfort of my terminal to manage my site.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-new-site&quot;&gt;The new site&lt;&#x2F;h2&gt;
&lt;p&gt;The last post that I wrote before refactoring my website, actually covers most
of my thoughts on this topic, so I&#x27;ll just mention what &quot;technologies&quot; I ended
up using for my new site.&lt;&#x2F;p&gt;
&lt;p&gt;In that post I mentioned that I wanted to migrate from a relational DB based
blog to an SSG system, and that&#x27;s what I ended up doing. I chose zola over other
SSGs because that&#x27;s the one that I found the most comfortable to use and the
most fitting for my needs, at least for now.&lt;&#x2F;p&gt;
&lt;p&gt;I could have just ended up making a completely static site with pure html and
would have also been better than using Django, but I find markdown to be much
more nicer to edit and read for simple texts, and I wanted to automate certain
things such as templating, without having to mess too much with it myself.&lt;&#x2F;p&gt;
&lt;p&gt;I also ended up using a CI&#x2F;CD system so that my site would get deployed and
built automatically each time that I push to master on my &quot;git server&quot;. I am
using Gitea as a kind of git server, and Drone as the CI&#x2F;CD system. So now all I
have to do when I want to publish a new article, is write the article, commit
the changes on my local repository, push the changes to Gitea on my master
branch, and then Drone will pick up the push event and automatically build and
deploy the updated site to my VPS.&lt;&#x2F;p&gt;
&lt;p&gt;The only significant problems that arose from this migration is that some URLs
have changed, notably the RSS URL, but also that the URLs for blog posts are no
longer under categories, but directly under the &#x2F;weblog&#x2F; URL. They can still be
accessed using the old URLs though, since I put some rewrite rules in nginx so
that it would redirect from the old URLs to the new format.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, I am much happier with my website and weblog now, and I hope that I
will be publishing some new stuff here, even if nobody really reads this.
Although in some cases that old bit might make it a bit more compelling to write
certain things :)&lt;&#x2F;p&gt;
&lt;p&gt;The source for my website is hosted at
&lt;a href=&quot;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;yaroslavps.com&quot;&gt;https:&#x2F;&#x2F;git.yaroslavps.com&#x2F;yaroslavps.com&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;2020-12-10: Updated some links&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Rethinking my weblog</title>
		<published>2020-03-07T02:44:00+00:00</published>
		<updated>2020-03-07T02:44:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/rethinking-my-blog/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/rethinking-my-blog/</id>
		<content type="html">&lt;p&gt;It&#x27;s been a while since I have posted anything on my weblog. I will be laying
out some of the reasons for this, as well as what I&#x27;ve been meaning to do with
my site and blog going forward.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;&#x2F;h2&gt;
&lt;p&gt;There are several reasons why I have neglected my weblog for the last year or
so. It certainly hasn&#x27;t been because of lack of imagination or content, since I
did have several different ideas I want to write about, and I still have
several drafts I started and still haven&#x27;t finished (most of which I probably
won&#x27;t finish). The biggest two reasons were that I became occupied with a lot
of different things including university, work, personal projects, hobbies,
procrastination, and well, life; and the second is honestly just laziness.&lt;&#x2F;p&gt;
&lt;p&gt;Now if I am completely honest I have to say that laziness is actually the
biggest factor of those two, especially considering that this laziness towards
my blog has been aggravated by my growing dislike of web (and other software
for that matter) in its current state. And that, ironically (or unironically)
includes my own blog and site, which run on Django using a blog engine I
personally developed.&lt;&#x2F;p&gt;
&lt;p&gt;Which also leads me to another problem related to the neglect of my weblog: the
neglect of my blog engine and Django app - w3blog. The causes and reasons for
the neglect of this project of mine - which I haven&#x27;t updated since January of
last year (much like the blog itself) - are essentially the same.&lt;&#x2F;p&gt;
&lt;p&gt;I am not going to go into details in this post as to how and&#x2F;or why I came to
dislike &quot;modern&quot; and &quot;mainstream&quot; software, but there are a couple details that
are relevant to this post. The most important of these is that I changed my
workflow quite drastically in the past couple of years, in a way that I believe
has made me much more productive using a computer. The second relevant detail
is bloat, and my dislike of it. What this basically means, is that I have come
to dislike the state and the way my site and blog operate.&lt;&#x2F;p&gt;
&lt;p&gt;The first annoying thing for me, is that I have to access the Django admin page
to author&#x2F;publish posts and articles, which is a kind of CMS for sites built
using the Django framework which my blog engine uses. It&#x27;s not a bad system per
se, and it is actually what other people that are more used to a Windows or
macOS-like workflow would call &quot;user-friendly&quot;. However, I&#x27;ve gotten really
used to vim, not only for programming, but also for everything else that
involves typing text. I use vim for writing articles, for University reports,
for composing emails, for editing config files; you get the idea. In general my
workflow has become much more keyboard-oriented, and web interfaces are just
not made to be operated with just a keyboard, which well, sucks for me.&lt;&#x2F;p&gt;
&lt;p&gt;The second thing which might not be as important from a pragmatical point of
view is bloat. By using Django for my site I am adding a lot of stuff that is
simply useless for my use-case. Actually for most projects, most of the
&quot;features&quot; of Django are just bloat, which is the case for most of these
do-it-all frameworks. I don&#x27;t mean to shit on Django, since I still find quite
fun and interesting to use simply because it&#x27;s so easy to build many kinds of
sites with it. However, the fact is that it is bloated.&lt;&#x2F;p&gt;
&lt;p&gt;So if for some reason you have read all of above, you now may be wondering.
Then why did you do it that way? Well, the reason is simple, I had different
preferences and opinions back when I started this weblog and its engine, and I
didn&#x27;t know better. Yes, I know about Flask, and I&#x27;ve used it for some
projects, but back when I started my blog engine, Django was what I knew how to
use best. I still would have ended up wanting to change the way my blog works,
simply because the way I use computers has changed so much in the past two
years.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The solution&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve been meaning to change the way my weblog functions for a long time, more
than a year actually. Over the course of this time I came up with different
ideas to better adapt the publishing of articles and posts to my usual
workflow.&lt;&#x2F;p&gt;
&lt;p&gt;One of the first ideas I came up with was making some kind of app or module for
Django that would allow me to access the Django admin&#x27;s functions over some
kind of TUI from my local machine without having to manually ssh each time I
wanted to make changes. I ended up giving up on this idea since I realized it
would just end up making everything more complicated, and I would spend a lot
time writing something which might not even be that useful in the end. In the
end I realized it would be better to completely change the back-end from the
ground up, since there was another goal that I wanted to achieve which was to
streamline, de-bloat and use a more minimal back-end.&lt;&#x2F;p&gt;
&lt;p&gt;The project to reform my weblog went into a kind of hiatus for some time, but a
couple of months ago I started to think about it once more. And so I started to
think what the ideal blog engine&#x2F;back-end for my 2020 self would be.&lt;&#x2F;p&gt;
&lt;p&gt;The idea that I ended up coming with was some sort of back-end that would read
markdown files - where each md file was a post or article, glue it to a
template and serve it. This way, I thought, I could just have a git repository
with all of my articles, and then I would merge and push to master each time
that I wanted publish something new, and then maybe by using some kind of CI,
the changes to master would be pulled automagically on the server.&lt;&#x2F;p&gt;
&lt;p&gt;After some digging around on the worldwide web, I realized that the ideas that
I had were (obviously) not new at all, and there already exists software that
works in precisely this way. This kind of software are called static site
generators (I&#x27;ll call them SSG for short). The three SSG that I found and
caught my attention were Jekyll, zola and Hugo.&lt;&#x2F;p&gt;
&lt;p&gt;Jekyll is the veteran of the three, and it&#x27;s even used by GitHub for GitHub
Pages. One other thing that I liked about it, is that it uses jinja (or
something similar) for templates. It seems pretty good to me, but it has a
couple nuisances for me. First of which is the fact that it is written in Ruby,
and I don&#x27;t know anything about Ruby. So if I wanted to take a look into the
code or tinker around with it I would be lost, or I would have to learn Ruby,
which I have no intention of doing.&lt;&#x2F;p&gt;
&lt;p&gt;Hugo seemed interesting to me because it&#x27;s written in Go, which is better than
Ruby, and which I would be much more willing to learn than Ruby if I had the
need (might actually even do it out if interest). However, Jekyll and zola both
uses a Jinja or Jinja-like template system, of which I am already familiar.
Another thing is that Hugo seems (at least to me) more complicated to configure
to your liking than Jekyll or zola.&lt;&#x2F;p&gt;
&lt;p&gt;zola is the one that caught my attention the most. I liked how simple it is to
set up, and the fact that it uses a Jinja-like template system; the fact it is
written in Rust, a language that I&#x27;ve recently started learning and that I&#x27;ve
come enjoy using. Another thing that liked about zola, especially compared to
Jekyll is the way it builds URLs, i.e. it doesn&#x27;t the outdated and useless
.html extension in the end, resulting in cleaner URLs. Maybe there is a way to
change this in Jekyll, but I didn&#x27;t find any information on it.&lt;&#x2F;p&gt;
&lt;p&gt;I haven&#x27;t decided yet which back-end to use, I might even write my own should I
decide that none of the above fulfill my needs. One thing is certain, I will
completely revamp my blog and site. After I finish revamping it, I will try my
best to write more constantly.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Packaging and distributing python apps and modules</title>
		<published>2019-01-31T08:10:00+00:00</published>
		<updated>2019-01-31T08:10:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/python-package-to-pypi/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/python-package-to-pypi/</id>
		<content type="html">&lt;p&gt;There may come a time after some hacking and playing around with python that
you feel like the piece of code you just created needs to be shared with the
world, and so you might be thinking &quot;Man, wouldn&#x27;t it be sweet if anyone could
install my app&#x2F;module just by typing &lt;code&gt;pip install stuffimade&#x27;&lt;&#x2F;code&gt;. Well, it is
actually easier than you might think (it certainly was in my case).&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;It basically boils down to these five things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Make an account on pypi.org&lt;&#x2F;li&gt;
&lt;li&gt;Come up with an original name, that hasn&#x27;t been taken on pypi (arguably the
hardest part of these instructions).&lt;&#x2F;li&gt;
&lt;li&gt;Prepare a setup py file to package your app&#x2F;module, choose a license, maybe
(preferably) write a readme.&lt;&#x2F;li&gt;
&lt;li&gt;Package it.&lt;&#x2F;li&gt;
&lt;li&gt;Upload it.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The first step is really simple, just go the website (pypi.org) and click on
the link that says &quot;Register&quot; on the top right corner. Be sure to not forget
your password, especially after uploading your package, since you will need
everything that you want to upload a new version of your package.&lt;&#x2F;p&gt;
&lt;p&gt;The second step is all up to you, just use the search function in the website
to make sure that your package name hasn&#x27;t been taken.&lt;&#x2F;p&gt;
&lt;p&gt;After having created your account on pypi.org, and decided on a name for your
app&#x2F;package, you&#x27;ll proceed to create the necessary package files. Your package
should consist of a folder with your actual module or app, inside which should
also be a &lt;code&gt;__init__.py&lt;&#x2F;code&gt; file (it can be empty if you don&#x27;t need to set any
variables or anything), a &lt;code&gt;LICENSE&lt;&#x2F;code&gt; file with your license of choice (e.g. MIT,
BSD, GPL, etc.), and a &lt;code&gt;README.rst&lt;&#x2F;code&gt; or &lt;code&gt;README.md&lt;&#x2F;code&gt; file containing a detailed
description of your app&#x2F;module.&lt;&#x2F;p&gt;
&lt;p&gt;Your directory structure should look something like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&#x2F;my-app-package
&lt;&#x2F;span&gt;&lt;span&gt;  &#x2F;my-app
&lt;&#x2F;span&gt;&lt;span&gt;    __init__.py
&lt;&#x2F;span&gt;&lt;span&gt;    (other files and directories)
&lt;&#x2F;span&gt;&lt;span&gt;  setup.py
&lt;&#x2F;span&gt;&lt;span&gt;  LICENSE
&lt;&#x2F;span&gt;&lt;span&gt;  README.md
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, if your app is going to have files other than python files, and the
aforementioned files, you might to add a &lt;code&gt;MANIFEST.in&lt;&#x2F;code&gt; in the root of you
package directory specifying the files to include. This is true, for example,
for Django apps, since they might contain template and static files (html, css,
js, etc.) that the packaging tool we are going to use might not pick up. As an
example I&#x27;ll show you the &lt;code&gt;MANIFEST.in&lt;&#x2F;code&gt; file of my w3blog package&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;include LICENSE
&lt;&#x2F;span&gt;&lt;span&gt;include README.md
&lt;&#x2F;span&gt;&lt;span&gt;recursive-include weblog&#x2F;static *
&lt;&#x2F;span&gt;&lt;span&gt;recursive-include weblog&#x2F;templates *
&lt;&#x2F;span&gt;&lt;span&gt;recursive-include weblog&#x2F;locale *
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There I specified to, just in case, include the &lt;code&gt;LICENSE&lt;&#x2F;code&gt; and &lt;code&gt;README.md&lt;&#x2F;code&gt;
files, and also include static files, templates, and the message files for
localization, by recursively searching the directories of said files.&lt;&#x2F;p&gt;
&lt;p&gt;Now on to the setup.py file. For this I am also going to use my project&#x27;s file
as an example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;os
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;setuptools &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;find_packages, setup
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(os.path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(os.path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;dirname&lt;&#x2F;span&gt;&lt;span&gt;(__file__), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;README.md&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;readme:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;README &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;readme.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# allow setup.py to be run from any path
&lt;&#x2F;span&gt;&lt;span&gt;os.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;chdir&lt;&#x2F;span&gt;&lt;span&gt;(os.path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;normpath&lt;&#x2F;span&gt;&lt;span&gt;(os.path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(os.path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;abspath&lt;&#x2F;span&gt;&lt;span&gt;(__file__), os.pardir)))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;setup&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;w3blog&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;0.5.2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;packages&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;find_packages&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;include_package_data&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;license&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BSD License&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;description&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;A simple blog engine for Django with multilingual capabilities.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;long_description&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;README&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;author&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Yaroslav de la Peña Smirnov&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;author_email&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;contact@yaroslavps.com&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;classifiers&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Environment :: Web Environment&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Framework :: Django&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Framework :: Django :: 1.11&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Framework :: Django :: 2.0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Framework :: Django :: 2.1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Intended Audience :: Developers&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;License :: OSI Approved :: BSD License&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Operating System :: OS Independent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3.4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3.5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3.6&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3.7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Topic :: Internet :: WWW&#x2F;HTTP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Topic :: Internet :: WWW&#x2F;HTTP :: Dynamic Content&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    ],
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, you should customize this file according to your app&#x27;s details, for
example, your classifiers list might look shorter, like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span&gt;    classifiers&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;License :: OSI Approved :: BSD License&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Operating System :: OS Independent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3.4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3.5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3.6&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Programming Language :: Python :: 3.7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    ],
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will depend on which version of python you want to support, your license,
some other required packages, etc. The rest of the setup function parameters
should be self explanatory.&lt;&#x2F;p&gt;
&lt;p&gt;Once you have you package files ready (don&#x27;t forget about your readme and
license), you&#x27;ll need to proceed to package them, i.e. generate the
distribution files. For that, we&#x27;ll need to install a couple of packages, we
cant install them inside a virtual environment, or you could install them
system wide&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo pip3 install&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; --upgrade&lt;&#x2F;span&gt;&lt;span&gt; setuptools wheel twine
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now just run the following command from the same directory where setup.py is
located&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; python3 setup.py sdist bdist_wheel
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After running that command, you should now have a dist subdirectory with a
.tar.gz archive and a .whl file. Those are the files that you&#x27;ll need to
upload. The twine package that we just installed is going to take care of that
for us. Remember that you already should have an account on pypi.org to upload
your package.&lt;&#x2F;p&gt;
&lt;p&gt;So for example, when I just uploaded the first version of w3blog, and each time
that I upload a new version I run a command (from the same directory as
setup.py) that looks like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; python3 twine upload dist&#x2F;w3blog-0.5.2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just replace &quot;w3blog-0.5.2*&quot; with your appropriate package name-version. After
running that command, twine is going to ask you for your username and password,
thence it is going to upload it to pypi. Once it is successfully uploaded, it
should be a matter of seconds or minutes before you, and everybody else in the
world with an internet connection (and capable of running python, of course),
can install your package!&lt;&#x2F;p&gt;
&lt;p&gt;If you need more detailed information about this process, check out the
official documentation at
&lt;a href=&quot;https:&#x2F;&#x2F;packaging.python.org&#x2F;tutorials&#x2F;packaging-projects&#x2F;&quot;&gt;https:&#x2F;&#x2F;packaging.python.org&#x2F;tutorials&#x2F;packaging-projects&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Intro to Linux and the Bash command line, pt III</title>
		<published>2019-01-11T08:23:00+00:00</published>
		<updated>2019-01-11T08:23:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/intro-to-linux-and-bash-pt3/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/intro-to-linux-and-bash-pt3/</id>
		<content type="html">&lt;p&gt;New year, new post. In this third, and most probably final part of these
tutorial&#x2F;guide series I will be mentioning some useful commands and programs
usually present in most standard linux installations. I will be talking
especially about programs&#x2F;commands to manipulate text output from programs and
files. I will also talk a little bit about regular expressions, a powerful tool
to perform searches inside text strings.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;filters&quot;&gt;Filters&lt;&#x2F;h2&gt;
&lt;p&gt;These programs that perform operations on input text and then write them to
standard output are commonly known as filters. You may already be familiar with
one of these commands, which the first one that I&#x27;m going to talk about.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cat&quot;&gt;cat&lt;&#x2F;h3&gt;
&lt;p&gt;This command allows you the see the content of a text file (or files). It
stands for con&lt;em&gt;cat&lt;&#x2F;em&gt;enate, and not for the house pet. The most basic use of this
command is to view the contents of a text file, just by typing cat followed by
the path of the file we wish to see. However, as it name implies, it also has
the ability to concatenate the contents of multiple text files, for example
text file &#x27;sample.txt&#x27;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; cat sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Tide&lt;&#x2F;span&gt;&lt;span&gt; Pods   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;JPEG&lt;&#x2F;span&gt;&lt;span&gt;    ok
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Despacito&lt;&#x2F;span&gt;&lt;span&gt;   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Bowsette&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Harold&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    coolest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Minions&lt;&#x2F;span&gt;&lt;span&gt; lamest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NPC&lt;&#x2F;span&gt;&lt;span&gt; cool
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And we want to concatenate its content with file &#x27;sample2.txt&#x27; to standard
output&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; cat sample.txt sample2.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Tide&lt;&#x2F;span&gt;&lt;span&gt; Pods   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;JPEG&lt;&#x2F;span&gt;&lt;span&gt;    ok
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Despacito&lt;&#x2F;span&gt;&lt;span&gt;   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Bowsette&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Harold&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    coolest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Minions&lt;&#x2F;span&gt;&lt;span&gt; lamest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NPC&lt;&#x2F;span&gt;&lt;span&gt; cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Troll&lt;&#x2F;span&gt;&lt;span&gt; Face  old
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Can&lt;&#x2F;span&gt;&lt;span&gt; haz chezburger  really old
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ROFLcopter&lt;&#x2F;span&gt;&lt;span&gt;  super old
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Dancing&lt;&#x2F;span&gt;&lt;span&gt; baby    ancient
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As usual, this command accepts different options, like for example the -n
option to display line&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; cat&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; sample.txt
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;  Pepe    cool
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;  Tide Pods   lame
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;  Uganda Knuckles cool
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;  Thanos  cool
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;  JPEG    ok
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;  Despacito   lame
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;  Bowsette    cool
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;  Harold  cool
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;  Sans    coolest
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;  Minions lamest
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;  NPC cool
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As always, you can check other options by looking up cat and any other command
with man, as explained in the previous part.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;head&quot;&gt;head&lt;&#x2F;h3&gt;
&lt;p&gt;This is a really simple command, it shows the first n lines of a text
file&#x2F;output. To use it, type head, followed by -n, then the number of lines to
show, and then the file. For example, let&#x27;s say we want to see the first 5
lines of sample.txt&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; head&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; 5 sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Tide&lt;&#x2F;span&gt;&lt;span&gt; Pods   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;JPEG&lt;&#x2F;span&gt;&lt;span&gt;    ok
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we use the command without passing the number of lines we wish to see, it
outputs the first 10 lines by default. For this just type head followed by the
path of the file.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tail&quot;&gt;tail&lt;&#x2F;h3&gt;
&lt;p&gt;Basically the same as head, except it shows the last lines. Let&#x27;s say we want
to see the last three lines&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; tail&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; 3 sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    coolest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Minions&lt;&#x2F;span&gt;&lt;span&gt; lamest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NPC&lt;&#x2F;span&gt;&lt;span&gt; cool
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As with head, the default is to output 10 lines.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sort&quot;&gt;sort&lt;&#x2F;h3&gt;
&lt;p&gt;This command is as obvious as it seems. It sorts output. For example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; sort sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Bowsette&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Despacito&lt;&#x2F;span&gt;&lt;span&gt;   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Harold&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;JPEG&lt;&#x2F;span&gt;&lt;span&gt;    ok
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Minions&lt;&#x2F;span&gt;&lt;span&gt; lamest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NPC&lt;&#x2F;span&gt;&lt;span&gt; cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    coolest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Tide&lt;&#x2F;span&gt;&lt;span&gt; Pods   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles cool
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;sed&quot;&gt;sed&lt;&#x2F;h3&gt;
&lt;p&gt;This one is a really powerful utility to transform and manipulate text,
however, to keep this tutorial short, I will only be showing a couple of the
most used cases. sed stands for &quot;stream editor&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;The way to use sed, is to pass it a kind of script (a sed script) that tells it
what to do with the text. The first and one of the most basic uses of sed, is
to basically perform the same task as head, to get the first n number of lines.
For example, let&#x27;s say we want the first 7 lines of sample.txt&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; sed &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;7q&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Tide&lt;&#x2F;span&gt;&lt;span&gt; Pods   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;JPEG&lt;&#x2F;span&gt;&lt;span&gt;    ok
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Despacito&lt;&#x2F;span&gt;&lt;span&gt;   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Bowsette&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course what I&#x27;ve just told it you it does is a simplification of what it
really does. Most accurately, the command or script that we passed to sed tells
it to output the first seven lines, and the q tells it to stop after that.&lt;&#x2F;p&gt;
&lt;p&gt;Another basic use of sed, and arguably the most common one, is to perform
search and replace operations on text. The basic syntax for this operations is
&#x27;s&#x2F;&lt;search&gt;&#x2F;&lt;replace&gt;&#x2F;&#x27; where &lt;search&gt; is the term you want to search for, and
&lt;replace&gt; is the term you wish to replace it with.&lt;&#x2F;p&gt;
&lt;p&gt;By default it will replace only the first occurrence in each line, however, we
can specify which or how many occurrences we want to replace by adding a number
and&#x2F;or letter to the end. For example, if we add a two
(&#x27;s&#x2F;&lt;search&gt;&#x2F;&lt;replace&gt;&#x2F;2&#x27;) it will replace only second occurrences of each
line.&lt;&#x2F;p&gt;
&lt;p&gt;But what if we want to replace each and every occurrence in all of the text?
For that we would use the letter g at the end. Let&#x27;s say for example, that we
want to replace all occurrences of &quot;cool&quot; in our sample.txt file, for &quot;dank&quot;.
In this case we would type something like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; sed &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;s&#x2F;cool&#x2F;dank&#x2F;g&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Tide&lt;&#x2F;span&gt;&lt;span&gt; Pods   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;JPEG&lt;&#x2F;span&gt;&lt;span&gt;    ok
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Despacito&lt;&#x2F;span&gt;&lt;span&gt;   lame
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Bowsette&lt;&#x2F;span&gt;&lt;span&gt;    dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Harold&lt;&#x2F;span&gt;&lt;span&gt;  dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    dankest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Minions&lt;&#x2F;span&gt;&lt;span&gt; lamest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NPC&lt;&#x2F;span&gt;&lt;span&gt; dank
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A thing to keep in mind, is that you should be enclosing the sed script in
single quotes. Of course these are only some of the most basic uses of this
command.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;grep&quot;&gt;grep&lt;&#x2F;h3&gt;
&lt;p&gt;This is the last program to manipulate text output that I want to mention. I
will demonstrate its basic use in this section, but I will show you a little
bit more about it in the next section when I will be writing about regular
expressions.&lt;&#x2F;p&gt;
&lt;p&gt;Back to grep, it is a program that basically searches a pattern that you give
it, and it will print to you the lines that contain that pattern. For example,
let&#x27;s say that we want to see only the cool (or dank) memes in our file to be
displayed&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; grep &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;cool&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  coolcharacter
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Bowsette&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Harold&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    coolest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NPC&lt;&#x2F;span&gt;&lt;span&gt; cool
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This line of text that we passed it, is actually the most basic form of regular
expression, of which we will be looking into detail next.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;regular-expressions&quot;&gt;Regular expressions&lt;&#x2F;h2&gt;
&lt;p&gt;A regular expression, or regex for short, is a string of text, that define a
search pattern for a larger set of text. Regexes are used in many programs,
such as in text editors, and search engines, and can be also of great use in
the terminal&lt;&#x2F;p&gt;
&lt;h3 id=&quot;an-intermission&quot;&gt;An intermission&lt;&#x2F;h3&gt;
&lt;p&gt;Before going into actual regular expressions in grep, I want to mention a
couple of characters that can make your life easier when dealing with files in
the terminal. They are called wildcards, and they are the asterisk (*) and the
question mark (?). If you&#x27;ve ever wondered why you can&#x27;t use those characters
in any of your files&#x27; names, that&#x27;s why.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ll start by explaining the asterisk. When you use the asterisk, you are
asking to look at or take all files that contain the any number of any
combination of symbols in the place where you put it. For example, we could be
looking at files that start with sa&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; ls sa&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;saturday.txt&lt;&#x2F;span&gt;&lt;span&gt; sample.txt sample2.txt sample.png
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or another example, we could be looking for files that just contain sa in their
name&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; ls &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;sa&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;asado.png&lt;&#x2F;span&gt;&lt;span&gt; saturday.txt sample.txt sample2.txt sample.png
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now the question mark. The question mark indicates that there should be a
character in its place, just any character. Let&#x27;s say that we want to see all
files with name &quot;sample&quot; that have a three character extension&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; ls sample.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;???
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;sample.txt&lt;&#x2F;span&gt;&lt;span&gt; sample.png
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Wildcards come really handy when you need to manipulate multiple files with
similar names. If the files that you wish to manipulate don&#x27;t really have
similar names, you might want to use curly braces to indicate a list of files
to manipulate, separated by commas. For example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; rm {monday.txt,december1999.txt,saturday.txt}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;back-to-regex&quot;&gt;Back to regex&lt;&#x2F;h3&gt;
&lt;p&gt;Now I&#x27;ll explain some things about regular expressions, and I&#x27;ll demonstrate
some basic uses with grep. Here are some basic concepts&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.&lt;&#x2F;code&gt; - The dot means a single character (any character). e.g. &#x27;be.r&#x27; would match
bear, beer, befr, etc.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;*&lt;&#x2F;code&gt; - The preceding element matches 0 or more times. e.g. &#x27;an*t&#x27; would match
at, ant, annt, annnt, etc.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;+&lt;&#x2F;code&gt; - The preceding element matches one or more times. e.g. &#x27;an+t&#x27; would match
ant, annt, annnt, etc.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;?&lt;&#x2F;code&gt; - The preceding element matches 0 or one time. e.g. &#x27;an?t&#x27; would match at,
and ant.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;{n}&lt;&#x2F;code&gt; - The preceding element matches exactly n times.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;{min, }&lt;&#x2F;code&gt; - The preceding element matches at least min times.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;{min, max}&lt;&#x2F;code&gt; - The preceding element matches at least min times, and no more
than max times.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;|&lt;&#x2F;code&gt; - The pipe, logical OR operator. e.g. &#x27;gray|grey&#x27; would match gray and grey&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;()&lt;&#x2F;code&gt; - The parenthesis group multiple characters as one element. e.g.
&#x27;gr(a|e)y&#x27; would match gray and grey.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[abc]&lt;&#x2F;code&gt; - It matches if a character is one of those inside the brackets.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[^abc]&lt;&#x2F;code&gt; - It matches if none of the characters is one of those inside the
brackets.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[a-d]&lt;&#x2F;code&gt; - A range of characters. i.e. a, b, c, or d.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;^&lt;&#x2F;code&gt; - Matches the beginning of the line.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;$&lt;&#x2F;code&gt; - Matches the end of the line.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So now let&#x27;s suppose for a practical example with grep, that we want to find
all lines that have &quot;cool&quot; or &quot;ok&quot; in them. In this case we would use the &quot;|&quot;
pipe symbol. However, if we use normal grep, we would have to escape the pipe
symbol like this &quot;|&quot;. That&#x27;s why it is better that we use &quot;grep -E&quot; to enable
extended regex, or its shorter alias &quot;egrep&quot;. It would look something like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; egrep &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;cool|ok&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;JPEG&lt;&#x2F;span&gt;&lt;span&gt;    ok
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Bowsette&lt;&#x2F;span&gt;&lt;span&gt;    cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Harold&lt;&#x2F;span&gt;&lt;span&gt;  cool
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    coolest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NPC&lt;&#x2F;span&gt;&lt;span&gt; cool
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s suppose, for another example, that we want to match those lines with a &#x27;t&#x27; as the last character&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; egrep &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;t$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; sample.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    coolest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Minions&lt;&#x2F;span&gt;&lt;span&gt; lamest
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I have already mentioned and shown you the use of regexes with grep (and&#x2F;or
egrep). Now I would like to show a more practical example with sed. Yes, sed
uses its own script language to alter text input, however, it also makes use of
regular expressions.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s suppose that we have a file that looks like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; cat shortcuts
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Some shortcuts
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;d       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Documents
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;D       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Downloads
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;m       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Music
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pp      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Pictures
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;vv      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Videos
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;s       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.scripts &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# My scripts
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;cf      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# My configs
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As we can see there is a lot of whitespace, and although comments might be of
help to humans, they are of no use to machine. Let&#x27;s begin by getting rid of
the comments, for that first need to remember the search and replace command of
sed, &#x27;s&#x2F;&lt;search&gt;&#x2F;replace&#x2F;g&#x27;, since we basically want to get rid of any
comment-looking string and replace it with, well, nothing. Now we have to think
of a regex that will match comments, for that &#x27;#.*&#x27; will do. What regex means
is, match &#x27;#&#x27; and everything after it. Now let&#x27;s put it together, and&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; sed &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;s&#x2F;#.*&#x2F;&#x2F;g&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; shortcuts
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;d       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Documents
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;D       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Downloads
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;m       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Music
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pp      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Pictures
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;vv      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Videos
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;s       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.scripts
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;cf      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.config
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Bam, there it is. However, we still have the blank lines left, and, if you pay
close attention, the comments have been deleted, but, the spaces that used to
be before some of the comments are still there.&lt;&#x2F;p&gt;
&lt;p&gt;So first, let&#x27;s improve our current sed command, if we want to match 0 or more
spaces (zero because not every comment has a space before it) we would use the
&lt;code&gt;*&lt;&#x2F;code&gt; symbol, but what symbol would we use for spaces? Well, that&#x27;s an easy one, in
sed we escape spaces like this &#x27;\s&#x27;, so now our sed command looks like this
&#x27;s&#x2F;\s*#.*&#x2F;&#x2F;g&#x27;.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take care of the last part, getting rid of blank lines. For this we would
need to issue a separate command, but fortunately we can stack commands in one
line with a semicolon (;). Now that we know that we need a way to match empty
lines with a regex, that&#x27;s very easy - &#x27;^$&#x27; just match the beginning and the
end of line together, after that, we add a sed command for deleting lines which
I haven&#x27;t mentioned (d), and our one liner is ready...&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; sed &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;s&#x2F;\s*#.*&#x2F;&#x2F;g; &#x2F;^$&#x2F;d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; shortcuts
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;d       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Documents
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;D       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Downloads
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;m       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Music
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pp      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Pictures
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;vv      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Videos
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;s       ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.scripts
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;cf      ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.config
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, issuing this command will not replace the original file, it will
simply output the result to the terminal screen. If you want to overwrite the
original file with the result of the sed command, you can pass sed the &#x27;-i&#x27;
option.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;piping-and-redirecting-output&quot;&gt;Piping and redirecting output&lt;&#x2F;h2&gt;
&lt;p&gt;This post is already getting too long, however there&#x27;s one more useful thing
about *nix systems that I&#x27;d like to mention - the pipeline. The pipeline in
Unix and Unix-like OSs is a chain of redirected output to the input of another
program. Along with that, there are operators to redirect standard output to
files (and viceversa).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;redirecting-to-and-from-files&quot;&gt;Redirecting to and from files&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s suppose that we want to repeat the last example, and want to clean the
file of comments and blank lines. We already now how to overwrite that file,
however, what if we want to save it to another file using common Unix operators
in bash. For that we can use the &#x27;&amp;gt;&#x27; and &#x27;&amp;gt;&amp;gt;&#x27; operators. For example, let&#x27;s we
want to save the result to a second file called &quot;shortcuts_clean&quot;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; sed &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;s&#x2F;\s*#.*&#x2F;&#x2F;g; &#x2F;^$&#x2F;d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; shortcuts &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; shortcuts_clean
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since there was no &quot;shortcuts_clean&quot; file, it has been created automatically.
However, if the file had already existed, it would have overwritten it, unless
we had used the &#x27;&amp;gt;&amp;gt;&#x27; operator, in that case, it would have appended the output
to the already existent file.&lt;&#x2F;p&gt;
&lt;p&gt;Just as there&#x27;s &#x27;&amp;gt;&#x27; to redirect TO files, there&#x27;s also the &#x27;&amp;lt;&#x27; to redirect from
files to a program&#x27;s standard input. However, must of the times you would just
pass the name&#x2F;path of the file to the program as an argument.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;piping&quot;&gt;Piping&lt;&#x2F;h3&gt;
&lt;p&gt;Now that we know how to redirect from and to files, we can learn how to
redirect from one program to another, with pipes. The pipe operator in *nix
systems is the vertical bar symbol (|). Let&#x27;s suppose that we want to see the
first three files in our current directory, for that, we can pipe the output of
ls into head, like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; ls &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;head&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span&gt; 3
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;asado.png
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;monday.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;sample.txt
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let&#x27;s get back to our sample.txt file. Let&#x27;s imagine that we first want to
sort our lines, and we want to preserve only those lines that contain &quot;cool&quot; or
&quot;lame&quot;. Then let&#x27;s suppose we want to modify to contain legit terms, and not
some antiquated boomer slang, so we want to replace cool with dank, and lame
with normie. Finally we want that to be output to a file instead of the screen.
Whew! Sounds like a lot of stuff to do, but it is quite simple, and it looks
like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; egrep &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;cool|lame&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; sample.txt &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;sort &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;sed &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;s&#x2F;cool&#x2F;dank&#x2F;g;s&#x2F;lame&#x2F;normie&#x2F;g&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; memes.txt
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So if we now take a look at the file...&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; cat memes.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Bowsette&lt;&#x2F;span&gt;&lt;span&gt;    dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Despacito&lt;&#x2F;span&gt;&lt;span&gt;   normie
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Harold&lt;&#x2F;span&gt;&lt;span&gt;  dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Minions&lt;&#x2F;span&gt;&lt;span&gt; normiest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NPC&lt;&#x2F;span&gt;&lt;span&gt; dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Pepe&lt;&#x2F;span&gt;&lt;span&gt;    dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Sans&lt;&#x2F;span&gt;&lt;span&gt;    dankest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Thanos&lt;&#x2F;span&gt;&lt;span&gt;  dank
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Tide&lt;&#x2F;span&gt;&lt;span&gt; Pods   normie
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Uganda&lt;&#x2F;span&gt;&lt;span&gt; Knuckles dank
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And that&#x27;s basically it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;post-scriptum&quot;&gt;Post scriptum&lt;&#x2F;h2&gt;
&lt;p&gt;Before ending it for good, I want to show some other programs that might be of
use in the Bash command line.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;less&quot;&gt;less&lt;&#x2F;h3&gt;
&lt;p&gt;This command might come in handy when there&#x27;s another command that outputs a
lot of text that overfills the terminal screen. You can pipe (as we have just
learned) the output of that command to less, so that you can navigate with your
arrow keys, or better yet with vim keys (hjkl). You can also search for terms
by typing slash (&#x2F;), just like with man.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tar&quot;&gt;tar&lt;&#x2F;h3&gt;
&lt;p&gt;This program is used in Linux to create and extract archives with the .tar
format, usually also compressing them using gunzip (.gz).&lt;&#x2F;p&gt;
&lt;p&gt;There usually two ways you will be using the program. One to extract files from
a compressed archive&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; tar&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -xzvf&lt;&#x2F;span&gt;&lt;span&gt; oldnotes.tar.gz
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the other to archive and compress files&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents&#x2F;notes$&lt;&#x2F;span&gt;&lt;span&gt; tar&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -czvf&lt;&#x2F;span&gt;&lt;span&gt; allnotes.tar.gz &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To learn more about the different options of this program, I recommend you
check the man pages of tar (&#x27;man tar&#x27;).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ssh-and-scp&quot;&gt;ssh and scp&lt;&#x2F;h3&gt;
&lt;p&gt;You may have already heard about ssh, which stands for &quot;secure shell&quot;, even if
you are new to Linux or Unix&#x2F;Unix-like systems. This program is used to connect
to other computers over a network (or the internet for instance), especially to
servers.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s suppose that you have a server with ip address 180.80.8.20 and your user
is tux&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$&lt;&#x2F;span&gt;&lt;span&gt; ssh tux@180.80.8.20
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, here we have assumed that the standard ssh port (22) is being used,
otherwise you will have to specify it by passing -p followed by the port
number.&lt;&#x2F;p&gt;
&lt;p&gt;Now let&#x27;s talk about scp, which stands for &quot;secure copy&quot;. This command uses the
same protocol as ssh, and it&#x27;s used to copy files from one computer to another
over a network. Let&#x27;s suppose that you want to copy a file from your current
computer to the server we used in the previous example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$&lt;&#x2F;span&gt;&lt;span&gt; scp somefile tux@180.80.8.20:&#x2F;home&#x2F;tux&#x2F;directory&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we were trying to do it the other way around, that is, from the remote
computer to your local computer, it would look like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$&lt;&#x2F;span&gt;&lt;span&gt; scp tux@180.80.8.20:&#x2F;home&#x2F;tux&#x2F;directory&#x2F;somefile directory&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just as with ssh, if you are not using standard port 22, you need to say to the
program to which port you are trying to connect, except that in the case of
scp, the flag is &#x27;-P&#x27; instead of &#x27;-p&#x27;, and goes right after &quot;scp&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Well, that&#x27;s it for this tutorial&#x2F;guide series, I really hope it was of use to
you.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Intro to Linux and the Bash command line, pt II</title>
		<published>2018-12-31T09:20:00+00:00</published>
		<updated>2018-12-31T09:20:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/intro-to-linux-and-bash-pt2/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/intro-to-linux-and-bash-pt2/</id>
		<content type="html">&lt;p&gt;So the year is coming to an end, and I didn&#x27;t follow up on the first part of
these mini tutorial&#x2F;guide&#x2F;introduction. Might as well end the year on a good
note and write at least one post this last month.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;In this part I will be writing about some more aspects of Linux and Unix-like
systems and tools that will come in handy when using the terminal. All or most
of these tools are a standard part of Linux and Unix&#x2F;Unix-like systems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;file-manipulation&quot;&gt;File manipulation&lt;&#x2F;h2&gt;
&lt;p&gt;I didn&#x27;t get into detail in the previous part of this guide on the file
manipulation side of things. However it is a crucial part of any computer
system, after all they wouldn&#x27;t be as useful as they are if you couldn&#x27;t create,
edit and delete files.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;create-files&quot;&gt;Create files&lt;&#x2F;h3&gt;
&lt;p&gt;Usually, the way you would go about creating and editing files is by using the
corresponding programs. Like for example, vim to create and edit text files.
However, there&#x27;s also a utility to create blank files called touch.&lt;&#x2F;p&gt;
&lt;p&gt;You can make a blank file by writing touch followed by the path of the file you
wish to create, like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ touch example.txt
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we have an empty file at &quot;&#x2F;home&#x2F;user&#x2F;example.txt&quot;. Although I kind of lied
when I said that this command is for making blank files. In reality, what it
does is check if such file exists, if it does, it modifies the date and time of
access and modification, otherwise it makes a new empty file, like in our case.
Most of the time you won&#x27;t really need this command, since you would actually be
creating files through programs or means, though it does come in handy
sometimes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;create-directories&quot;&gt;Create directories&lt;&#x2F;h3&gt;
&lt;p&gt;Now on to something more interesting, making directories. This one is quite
simple, and the command for that is mkdir. For example&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ mkdir foo
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case we have created a new folder called &quot;foo&quot; in &quot;&#x2F;home&#x2F;user&#x2F;&quot;. But
remember that we are passing paths here, which can be relative or absolute (if
you don&#x27;t know or remember what this means, check the first part of this guide).
In our case  we were using a relative path, with just the name of the directory
to create.&lt;&#x2F;p&gt;
&lt;p&gt;If we were to indicate an absolute path like &quot;&#x2F;home&#x2F;user&#x2F;foo&quot; we would need to
make sure that directories &quot;home&quot; and &quot;user&quot; already exist. However, there&#x27;s a
useful argument we can pass to mkdir to make parent directories if needed, -p&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ mkdir -p &#x2F;tmp&#x2F;foo&#x2F;bar
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, if directory &quot;foo&quot; doesn&#x27;t exist, mkdir will make it for us along
with &quot;bar&quot; inside it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;moving-and-renaming&quot;&gt;Moving and renaming&lt;&#x2F;h3&gt;
&lt;p&gt;This one is pretty simple, and both actions are handled by the same command, mv,
which is short for move.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to rename a file or directory, simply &quot;move&quot; it to the same
destination directory with a new&#x2F;different name, for example&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ mv untitled titled
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you want to move it to a different location, just indicate that path as the
second argument. Remember that we are using paths here, and we use either
absolute or relative paths&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ mv titled Documents&#x2F;titled
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;copying&quot;&gt;Copying&lt;&#x2F;h3&gt;
&lt;p&gt;Copying files is similar to moving them, except that the command is different,
cp&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ cp titled Documents&#x2F;titled2
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, copying directories is different. To copy directories you have to use a
special flag, the -r flag. This flag means that the operation ought to be
recursive, that is to copy every file and subdirectory in that directory along
with the directory (and files in those subdirectories and files the
subdirectories of the subdirectories and... yeah recursion, you get it) to the
destination path. So we would do something like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ cp -r dir dir-copy
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;removing&quot;&gt;Removing&lt;&#x2F;h3&gt;
&lt;p&gt;Removing files is pretty simple, just use rm followed by the path of the file,
for example&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ rm title
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, removing directories is a little bit trickier. One option would be to
use the command rmdir, however, the directory has to be empty before you can
remove it.&lt;&#x2F;p&gt;
&lt;p&gt;The second option, is to use the same command as we used with files, but passing
it the -r flag so that it removes files recursively, similar to what we did with
the copy (cp) command. Do watch out, as it will remove the directory along with
everything that is in it.&lt;&#x2F;p&gt;
&lt;p&gt;So to remove a directory and everything in it, we input something like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ rm -r dir
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This command also has another flag to forcefully remove files without prompting,
the -f flag. This might be useful when you are removing files recursively and
there might be some special files, like hidden files (the ones with a dot as the
first character) and you don&#x27;t want to be prompted for each and everyone of
them.&lt;&#x2F;p&gt;
&lt;p&gt;Thread REALLY carefully when using this command though, especially if you are
issuing it as root. You don&#x27;t wanna issue a &quot;sudo rm -rf &#x2F;&quot; and end up with a
borked system and lost files. Unless you are some kind of sadist or something.&lt;&#x2F;p&gt;
&lt;p&gt;An example of when it might be useful, is when you need to delete a git
repository from your computer, since it contains a lot of special hidden files
which git uses to keep track of your commits and other stuff. So to remove it,
we do&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~$ rm -rf somerepo
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;permissions&quot;&gt;Permissions&lt;&#x2F;h3&gt;
&lt;p&gt;The Unix or Unix-like user and permissions systems, is a robust system for
managing what particular users can do with certain files and directories. This
allows to create a secure environment, especially when there are multiple users
using one computer.&lt;&#x2F;p&gt;
&lt;p&gt;Every file has three types of permissions which dictate what can be done with
it. Each permission is represented by a single letter&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;r - read: the user can read&#x2F;view the file.&lt;&#x2F;li&gt;
&lt;li&gt;w - write: the user can write&#x2F;modify (this includes deleting) the file.&lt;&#x2F;li&gt;
&lt;li&gt;x - execute: the file can be run or executed by the user, if it is a program
or script.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There are as well three different sets of people the permissions and ownership
might apply to. These are&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;u - user&#x2F;owner: the one user that owns the file. Usually it is the user that
created the file, but ownership can be modified.&lt;&#x2F;li&gt;
&lt;li&gt;g - group: every file has a group it belongs to. The group can be a one user
group (every user has their own one-user group), or a common group with
multiple users.&lt;&#x2F;li&gt;
&lt;li&gt;o - others: everybody else who is not either in the group or the owner.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you read the first part of this guide you might remember that I mentioned
using the command &quot;ls -l&quot; to list the contents of the directory with details
about the files, including permissions&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~&#x2F;Documents$ ls -l
&lt;&#x2F;span&gt;&lt;span&gt;drwxr-xr-x  2 user user  4.0K Jul  18 04:20 Books
&lt;&#x2F;span&gt;&lt;span&gt;-rwxr-xr--  1 user group 350  Jul  18 04:20 run.py
&lt;&#x2F;span&gt;&lt;span&gt;-rw-r--r--  1 user user  1.2M Jul  18 04:20 picture.png
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As mentioned in the first part, the first ten characters of a row of the output
is what tells us about the permissions of the given file in that row.&lt;&#x2F;p&gt;
&lt;p&gt;The first character in that sequence tells us if it is a normal file, or a
directory. If it has a d, it is a directory (duh), if it has a dash, it is a
normal file. It can be another letter, like an l for a symbolic link (a topic
for another day).&lt;&#x2F;p&gt;
&lt;p&gt;The next 9 characters are divided in subsequences of three letters, each for a
set of people. The first three characters after the file type one are the
permissions for the owner, the next three are for the group, and the last three
for others.&lt;&#x2F;p&gt;
&lt;p&gt;In each of this subset of three characters, the permissions are in the order of
read, write, and execute. So a letter means that that said set of users have
said permission, and its absence means the lack of that permission.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take for example the &quot;run.py&quot; file. By the information there we can see
that it is a normal file (no d (that&#x27;s what she said)), its owner (user) can
read, write and even execute it; the group users (in group group) can read and
execute it, but not write to it; and the others can just take a look at its
contents.&lt;&#x2F;p&gt;
&lt;p&gt;You might have noticed that directories tend to have the &quot;x&quot; part of the
permissions, however, this means something a little bit different on directories
than on files. It doesn&#x27;t mean that you can execute but rather that you can
&quot;search it&quot;, or in other words, access files inside of it. Because having the
&quot;read&quot; permission on a directory only means that you can take a look at what
files are inside of it, and write that you can put files inside the directory.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;changing-permissions&quot;&gt;Changing permissions&lt;&#x2F;h3&gt;
&lt;p&gt;There is a really useful command that allows us to change permissions on files,
chmod. It is short for change file mode bits.&lt;&#x2F;p&gt;
&lt;p&gt;To change the permissions on the file you input chmod followed by the
permissions and the path of the file. There are two ways of setting the
permissions, the easy and long one using letters, and the short but not as easy
way with octal &quot;permission bits&quot;. We&#x27;ll take a look at the easy one first.&lt;&#x2F;p&gt;
&lt;p&gt;The easier way is made up of three parts&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Who - user&#x2F;owner, group, others or all (u, g, o, or a)&lt;&#x2F;li&gt;
&lt;li&gt;Revoke or grant, &quot;+&quot; to grant, &quot;-&quot; to revoke&lt;&#x2F;li&gt;
&lt;li&gt;The permission we are setting - read, write or execute (r, w, or x)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So let&#x27;s suppose we have a script we want to set the execute permission for so
that any user in the computer can execute it.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~&#x2F;Documents&#x2F;stuff$ ls -l
&lt;&#x2F;span&gt;&lt;span&gt;-rw-r--r-- 1 user group  420  April 20 6:59  script.sh
&lt;&#x2F;span&gt;&lt;span&gt;user@host:~&#x2F;Documents&#x2F;stuff$ chmod a+x script.sh
&lt;&#x2F;span&gt;&lt;span&gt;-rwxr-xr-x 1 user group  420  April 20 6:59  script.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As we can see, after executing the command, every user on the computer now has
execute permission on the script. Now let&#x27;s say that we want to revoke read
permissions for everybody except for the owner (user), we could execute o-r and
then g-r, but we can also combine them, like so&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~&#x2F;Documents&#x2F;stuff$ chmod go-r script.sh
&lt;&#x2F;span&gt;&lt;span&gt;-rwx--x--x 1 user group  420  April 20 6:59  script.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now onto the short way. This one&#x27;s a bit harder to remember as you have to have
some understanding of binary. Basically the way it works is that you set the
permissions by passing three octal numbers (i.e., 0-7) that each represent the
permission bits for each set of people (user&#x2F;owner, group, others).&lt;&#x2F;p&gt;
&lt;p&gt;As it is we have three possible permissions (read, write and execute) and 2^3
just so happens to be 8 (possible combinations), that&#x27;s why it is in octal.
Here&#x27;s a table to help you out&lt;&#x2F;p&gt;
&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Octal&lt;&#x2F;td&gt;
      &lt;td&gt;Binary&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;0&lt;&#x2F;td&gt;
      &lt;td&gt;001&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;&#x2F;td&gt;
      &lt;td&gt;001&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;&#x2F;td&gt;
      &lt;td&gt;010&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;&#x2F;td&gt;
      &lt;td&gt;011&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;&#x2F;td&gt;
      &lt;td&gt;100&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;5&lt;&#x2F;td&gt;
      &lt;td&gt;101&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;6&lt;&#x2F;td&gt;
      &lt;td&gt;110&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;7&lt;&#x2F;td&gt;
      &lt;td&gt;111&lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
  &lt;&#x2F;tbody&gt;
&lt;&#x2F;table&gt;
&lt;p&gt;Basically what this means, is that when we have a 1, said permission is granted,
when it is 0, it is not. So for example, 6 means that read and write have been
granted, but not execute, because 6 =&amp;gt; 110 =&amp;gt; rw-.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s say for example that we want to set the permissions of file so that the
owner can read, write, and execute, the group can read and execute, and others
can only execute. It would look something like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~&#x2F;Documents&#x2F;stuff$ chmod 751 script.sh
&lt;&#x2F;span&gt;&lt;span&gt;user@host:~&#x2F;Documents&#x2F;stuff$ ls -l
&lt;&#x2F;span&gt;&lt;span&gt;-rwxr-x--x 1 user group  420  April 20 6:59  script.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you are changing the permissions of a directory, the permissions will apply
only to the directory itself and not to the files and subdirectories inside of
it, unless you use the recursive flag -R (note that in the case of chmod and
chown it is a capital R).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;changing-ownership&quot;&gt;Changing ownership&lt;&#x2F;h3&gt;
&lt;p&gt;Changing the owner of a file is easier than changing permissions, since less
variables are involved. To change owner we use the chown command, for example,
change the user that owns a file&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~&#x2F;.logs$ ls -l
&lt;&#x2F;span&gt;&lt;span&gt;-rw-r--r-- 1 root root  69  April 20 6:59  some.log
&lt;&#x2F;span&gt;&lt;span&gt;user@host:~&#x2F;.logs$ sudo chown user some.log
&lt;&#x2F;span&gt;&lt;span&gt;user@host:~&#x2F;.logs$ ls -l
&lt;&#x2F;span&gt;&lt;span&gt;-rw-r--r-- 1 user root  69  April 20 6:59  some.log
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As the file doesn&#x27;t belong to the same user initially, we need to use sudo
elevate our permissions to &quot;super user&quot;. Note that in order to be able to use
sudo or &quot;elevate your permissions&quot; your user needs to be either in the sudoers
file or in other distros in the &quot;wheel&quot; group, or both. I won&#x27;t go into details
on how to do that, since most probably your user is already in the sudoers file,
and a quick search on the internet will give you the information needed.&lt;&#x2F;p&gt;
&lt;p&gt;Now let&#x27;s say that you wanted to change both the user and group that file
belongs to, we would do like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~&#x2F;.logs$ ls -l
&lt;&#x2F;span&gt;&lt;span&gt;-rw-r--r-- 1 root root  69  April 20 6:59  some.log
&lt;&#x2F;span&gt;&lt;span&gt;user@host:~&#x2F;.logs$ sudo chown user:group some.log
&lt;&#x2F;span&gt;&lt;span&gt;user@host:~&#x2F;.logs$ ls -l
&lt;&#x2F;span&gt;&lt;span&gt;-rw-r--r-- 1 user group  69  April 20 6:59  some.log
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just as with chmod, if you want to change ownership recursively in a directory,
you need to use the -R flag.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;epilogue-some-tips&quot;&gt;Epilogue&#x2F;Some tips&lt;&#x2F;h2&gt;
&lt;p&gt;I forgot to mention in the previous part how to write paths with spaces. You
cannot write paths with spaces just like that, since spaces are treated as the
separator between arguments.&lt;&#x2F;p&gt;
&lt;p&gt;There are two ways of writings paths and filenames (and other arguments) with
spaces. One is to put the argument between quotation marks, like for example&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~&#x2F;Documents$ rm &amp;quot;Shopping List.txt&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another is to use an escape character, i.e. just put a backslash () before the
space, like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user@host:~&#x2F;Documents$ rm Shopping\ List.txt
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;One more thing that I wanted to mention is the man(ual) pages. Basically all
Linux distros come with man pages.&lt;&#x2F;p&gt;
&lt;p&gt;You don&#x27;t always have to resort to the internet if you don&#x27;t remember how to use
a command, like what flags a command accepts, what are the order of the
arguments, etc. You might not have internet one day, and you might to resort to
good ol&#x27; offline resources, and the man pages are a good one.&lt;&#x2F;p&gt;
&lt;p&gt;Besides, it is sometimes faster and easier to not have to leave the terminal to
look up the information.&lt;&#x2F;p&gt;
&lt;p&gt;To read the man(ual) pages of a command, input &quot;man&quot; followed by the name of the
command, e.g. &quot;chmod&quot;, and it will provide you with almost all the information
that you need.&lt;&#x2F;p&gt;
&lt;p&gt;You can use vim keys (hjkl), or the arrow keys to scroll. Type &#x2F;&lt;word&gt; to search
for that word, and afterwards press n to find the next found item.&lt;&#x2F;p&gt;
&lt;p&gt;This is all for this part. Happy 2019!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Intro to Linux and the Bash command line</title>
		<published>2018-11-05T23:53:00+00:00</published>
		<updated>2018-11-05T23:53:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/intro-to-linux-and-bash/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/intro-to-linux-and-bash/</id>
		<content type="html">&lt;p&gt;Recently I decided to introduce a friend of mine to the wonderful world of
Linux, and like when someone moves to a completely new town, you have to help
that friend get around town and learn about how things work in this new town,
where are all the places of interest, etc. And so it is, in someway, when
someone decides to make the move to a new OS, they have to get used to the new
environment and make new habits, especially regarding Linux. Therefore, I
decided to write this tutorial for my friend, and anybody who decided to try
Linux, and want to learn to use more effectively, that is, with a higher level
of skill than an average user.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Most probably you already know, but Linux is not actually the OS itself, but
rather the kernel that is used in conjuction with a collection of programs and
packages called GNU (insert here jokes and memes about GNU&#x2F;Linux (or
GNU+Linux)), and there are many different distributions (over 9000) of said
GNU&#x2F;Linux.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re just about to install Linux, and haven&#x27;t decided yet on a distro, here
I wrote a small list of distros that might start with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Manjaro - I personally use this distro. This one has different releases, with
different Desktop Environments (or DEs), like KDE or GNOME. This is a &quot;rolling
release&quot;, what that means, is that instead of the classical update to version
x.x of the OS system, updates for each package are being rolled out
constantly, and sepparatly for each package. That is, you get basically the
latest packages, with the latest updates, at the cost of maybe some stability.
It is quite easy to get installed, and get started with (If you choose an
official release like Manjaro KDE or Manjaro GNOME).&lt;&#x2F;li&gt;
&lt;li&gt;Ubuntu - The most know Linux distribution. It is one of the most
&quot;user-friendly&quot; distros out there. It is more stable than Manjaro (although
not always, unless you&#x27;re using the Long-Term Support versions). If you just
want to install an OS where everything just works, and is already configured
for you, and you don&#x27;t want to choose from a list of DEs (or you don&#x27;t know
what a Desktop Environment is), this will most probably suit your needs.&lt;&#x2F;li&gt;
&lt;li&gt;Debian - One the most stable distributions. It is not as easy to install as
Ubuntu or Manjaro due to large ammount of choice given during installation,
but it&#x27;s not really hard to either. Actually, Ubuntu is derived from Debian.
You must probably will have to configure it to your needs and likings
(personally, I dislike the default settings of GNOME), but if you want real
stability, and distro that has been around almost as long as the kernel
itself, then this might be the distro for you. One downside of Debian, is that
because of its focus on stability, many packages on the main (stable)
branch&#x2F;version are quite old&#x2F;outdated. Another con of Debian, is that it
doesn&#x27;t include &quot;non-free&quot; packages in the main repository (that is, there are
no proprietary packages by default), so if need a proprietary program or
package, like nvidia&#x27;s drivers, you will have to add the corresponding
repositories by yourself.&lt;&#x2F;li&gt;
&lt;li&gt;Fedora - It is similar to Ubuntu regarding stability and ease of use (i.e.
quite simple to use). I can&#x27;t say much about Fedora, because I haven&#x27;t used it
that much myself, but it is a very popular distribution. It has the same con
as Debian, in that it doesn&#x27;t include &quot;non-free&quot; software in its main
repository.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you found &quot;Desktop Environment&quot; to be a unfamiliar term, in a nutshell, it is
the collection of programs and packages that present with the Graphical User
Interface for interaction with the system. How your OS&#x2F;distribution is going to
look like doesn&#x27;t depend as much on the distro itself, as on the DE that you
choose to install or comes with the distro.&lt;&#x2F;p&gt;
&lt;p&gt;Do you have Linux installed? Excellent, now we can get started.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;file-structure&quot;&gt;File structure&lt;&#x2F;h2&gt;
&lt;p&gt;If you are used to working with Windows systems, the the first thing that you
might notice is the difference in how files are handled&#x2F;organized. In Windows,
because of its DOS legacy, drive letters are used to represent different drives,
partitions and file systems. In Linux, like in other Unix-like systems (e.g.
macOS, BSD) this differs somewhat.&lt;&#x2F;p&gt;
&lt;p&gt;In Linux, everything is a file, including the devices that are connected to your
computer. From your keyboard (which is a read-only file) to your drives.
Directories are also files.&lt;&#x2F;p&gt;
&lt;p&gt;Different disks or drives are mounted in a specific directory, and from this
directory, every file from that drive will be accessible. You can mount and
unmount drives yourself, but if you installed a distro with any of the most
popular desktop environments, then there&#x27;s nothing to worry about, the system is
going to take care of mounting your pendrive for you, and creating a shortcut in
your file explorer and&#x2F;or desktop each time you insert it.&lt;&#x2F;p&gt;
&lt;p&gt;Linux has what is called a &quot;root&quot; directory&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In there are the files and subdirectories in your system are located, including
drives mounted in a specific subdirectory as mentioned before.&lt;&#x2F;p&gt;
&lt;p&gt;Each user in Linux has its own &quot;home&quot; directory. Inside your home directory your
personal documents&#x2F;files and subdirectories are going to be stored. All the home
directories of each user are usually going to be stored inside the &quot;&#x2F;home&#x2F;&quot;
directory. For example, for user &quot;user&quot;, their home directory is going to be&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&#x2F;home&#x2F;user
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, you can also move to your home directory by using the symbol ~. For
example, in your terminal, if you input&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; cd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;~
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You are going to be taken to your home directory (e.g. &quot;&#x2F;home&#x2F;user&#x2F;&quot;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-command-line-bash&quot;&gt;The command-line - Bash&lt;&#x2F;h2&gt;
&lt;p&gt;Arguably the most useful program in Linux and any *nix system is the terminal.
Yes, maybe the average user won&#x27;t have to use it, but it is the most flexible,
effective and useful instrument in your computer. A lot of work can be done
faster and more effectively in the terminal, rather than in a GUI. Obviously, it
is faster to learn to use a graphical interface, than a text-based or
command-line one, however, once you learn to properly use the terminal, you will
be able to use computer more efficiently than ever.&lt;&#x2F;p&gt;
&lt;p&gt;Your command-line, if you haven&#x27;t changed any defaults, will most probably look
something like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first part before the &quot;@&quot; symbol, is the user with whom you have logged in.
After the &quot;@&quot; symbol is the &quot;hostname&quot; of your machine, i.e. the name of your
computer in a network.&lt;&#x2F;p&gt;
&lt;p&gt;After the semicolon &quot;:&quot;, the directory in which you are currently located is
going to be displayed. In our case, the &quot;~&quot; symbol is displayed, meaning that we
are inside our home directory. If you wish to see the full absolute path in
which you are located, you can input the command &quot;pwd&quot;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$&lt;&#x2F;span&gt;&lt;span&gt; pwd
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;&#x2F;home&#x2F;user
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The dollar &quot;$&quot; symbol, tells us that we are logged in as &quot;normal&quot; user. In Linux
and all *nix systems, there is a so called &quot;super user&quot;, or just the &quot;root&quot; user
for short. Normal users don&#x27;t have full access to all of the files in the
system, including other users&#x27; files. The root user has full access to all
system files. When you are logged in as the root user, the dollar &quot;$&quot; symbol is
going to be replaced by the hash &quot;#&quot; symbol.&lt;&#x2F;p&gt;
&lt;p&gt;However, we will be talking about the root user and permissions another time.&lt;&#x2F;p&gt;
&lt;p&gt;I can&#x27;t tell you exactly how to open the terminal, as it is different in each
distro and desktop environment. You will have to look for the link that says
&quot;Terminal&quot; in your programs&#x27; menu, with the icon of a terminal on it.&lt;&#x2F;p&gt;
&lt;p&gt;To be able to start working in the terminal, we&#x27;ll need to become acquainted
with some of the main commands used for navigating.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;navigation-in-the-terminal&quot;&gt;Navigation in the terminal&lt;&#x2F;h3&gt;
&lt;p&gt;There is one more thing that needs to be taken into consideration when working
with Linux and Unix-like systems, and that is, case-sensitivity. *nix systems
are case-sensitive, in contrast to Windows ones, which aren&#x27;t. What that means,
is that, if on Windows, files &quot;README.TXT&quot; and &quot;readme.txt&quot; are the same file,
in Linux and Unix they are completely different files.&lt;&#x2F;p&gt;
&lt;p&gt;To move around directories, we use the &quot;cd&quot; (or change directory) command,
followed by the name, or path of the directory. The directory can be absolute or
relative.&lt;&#x2F;p&gt;
&lt;p&gt;A relative path, is, for example, the name of a subdirectory inside the
directory in which we are currently located. In other words, the path relative
to where we are located.&lt;&#x2F;p&gt;
&lt;p&gt;An absolute path, is the path relative to the root directory.&lt;&#x2F;p&gt;
&lt;p&gt;For example, if we want to move to the &quot;Documents&quot; directory inside
&quot;&#x2F;home&#x2F;user&#x2F;&quot;, and we are already at &quot;&#x2F;home&#x2F;user&#x2F;&quot;, the we can just type the
following&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$&lt;&#x2F;span&gt;&lt;span&gt; cd Documents
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we wanted to move to that same directory from another location in the system,
we would type&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:&#x2F;var$&lt;&#x2F;span&gt;&lt;span&gt; cd &#x2F;home&#x2F;user&#x2F;Documents
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To move one folder up, we write &quot;..&quot;. Example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents$&lt;&#x2F;span&gt;&lt;span&gt; cd ..
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The two dots &quot;..&quot;, means the root directory of the current subdirectory. One dot
&quot;.&quot; means the current directory.&lt;&#x2F;p&gt;
&lt;p&gt;There is one more command, that will aid you in navigating - ls. This command
outputs a list of files and directories in the current location&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents$&lt;&#x2F;span&gt;&lt;span&gt; ls
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Books&lt;&#x2F;span&gt;&lt;span&gt;       todo.txt    picture.png
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This command also accepts arguments and flags. For example, to list hidden files
as well, add the &quot;-a&quot; flag&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents$&lt;&#x2F;span&gt;&lt;span&gt; ls&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -a
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Books&lt;&#x2F;span&gt;&lt;span&gt;    .secret    todo.txt    picture.png
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hidden files in Linux start with a dot (e.g., hidden directory &quot;.secret&quot;).&lt;&#x2F;p&gt;
&lt;p&gt;There is also the &quot;-l&quot; parameter, which shows us a list of the contents with
additional information, such as, permissions (more on that in the next part),
amount of files inside a directory, owner of the file (user and group), size on
disk, datetime of creation&#x2F;modification, and the name of the file. Example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents$&lt;&#x2F;span&gt;&lt;span&gt; ls&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -l
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;drwxr-xr-x&lt;&#x2F;span&gt;&lt;span&gt;  2 user user 4.0K Jul  18 04:20 Books
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span&gt;  1 user user 350  Jul  18 04:20 todo.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span&gt;  1 user user 1.2M Jul  18 04:20 picture.png
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can mix flags as well,&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents$&lt;&#x2F;span&gt;&lt;span&gt; ls&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -al
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;drwxr-xr-x&lt;&#x2F;span&gt;&lt;span&gt;  2 user user 4.0K Jul  18 04:20 Books
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;drwxr-xr-x&lt;&#x2F;span&gt;&lt;span&gt;  5 user user 4.0K Jul  18 04:20 .secret
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span&gt;  1 user user 350  Jul  18 04:20 todo.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span&gt;  1 user user 1.2M Jul  18 04:20 picture.png
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also take a look at what is inside a directory without having to move to
it first, by passing along as the last argument the name&#x2F;path of said directory,
for example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~&#x2F;Documents$&lt;&#x2F;span&gt;&lt;span&gt; ls&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span&gt; Books
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;drwxr-xr-x&lt;&#x2F;span&gt;&lt;span&gt; 12 user user 4.0K Jul  18 04:20 Lessons
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span&gt;  1 user user 2.3M Jul  18 04:20 Crime and Punishment.pdf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;shortcuts&quot;&gt;Shortcuts&lt;&#x2F;h3&gt;
&lt;p&gt;Before we conclude the first part of this tutorial, I would like to mention some
useful &quot;shortcuts&quot; in bash.&lt;&#x2F;p&gt;
&lt;p&gt;The first one is command history. Each time you input a command into the
terminal, it saves it in a history file. You can move around your command
history by using the up and down arrows. Let&#x27;s say you want to repeat the last
command you used, instead of typing it all over again, you could just hit the up
arrow one time, maybe modify it a bit, and then press enter to input it. If you
want to use an older command, you can press the up arrow multiple times, and if
you missed the command you needed, you can go forward in your history by
pressing the down arrow.&lt;&#x2F;p&gt;
&lt;p&gt;There is one more useful thing in Bash - Tab completion. When you press the
&quot;Tab&quot; key, bash will try to autocomplete the command for you.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s say, for example, that you are in the root directory and you want to move
to &quot;&#x2F;home&#x2F;user&#x2F;&quot;. you can start typing &quot;cd h&quot;, then press &quot;Tab&quot;, so you now have
&quot;cd home&#x2F;&quot;, now type &quot;u&quot;, press &quot;Tab&quot; one more time, and now you have &quot;cd
home&#x2F;user&#x2F;&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;If there are multiple possible options to be autocompleted, then on the first
hit of the &quot;Tab&quot; key you are not going to get anything. If you don&#x27;t get
anything it could also mean that there are nothing to autocomplete. In the first
case, if you press &quot;Tab&quot; twice, bash is going to output a list of possibilities,
for example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$&lt;&#x2F;span&gt;&lt;span&gt; cd Do
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;Documents&#x2F;&lt;&#x2F;span&gt;&lt;span&gt; Downloads&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;user@host:~$&lt;&#x2F;span&gt;&lt;span&gt; cd Do
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, we can type the next letter, for example &quot;cd Doc&quot;, and press &quot;Tab&quot;
one more time, and we are going to get &quot;cd Documents&#x2F;&quot;. However, if you didn&#x27;t
get anything on pressing &quot;Tab&quot; twice, it means that is nothing to autocomplete.&lt;&#x2F;p&gt;
&lt;p&gt;It can be a little be hard to understand at first how &quot;Tab completion&quot; works,
but the best way to understand it, by trying it yourself.&lt;&#x2F;p&gt;
&lt;p&gt;That is all for now, in the next part I am going to talk more about working on
the terminal.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Setting up your own VPN</title>
		<published>2018-11-02T05:43:00+00:00</published>
		<updated>2018-11-02T05:43:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/your-own-vpn/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/your-own-vpn/</id>
		<content type="html">&lt;p&gt;There are many reasons why you would want to use a VPN, especially in this day
and age. The major one would be to securely and more privately surf the web, but
that is far from the only reason. I for one use it as well to be able to set up
a remote network with my desktop PC while I&#x27;m away from home, so that I can
access all of my files through SSH. There are a ton of other reasons as to why a
VPN could be useful, but that is not the topic of this post, rather I will be
writing here about to set up your own VPN (yes your own!) on a VPS, or any other
kind of linux server for that matter, using OpenVPN.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;I am in fact running my own VPN in the same server that I use to host this site
and other projects of mine. However due to certain circumstances I need to
migrate to another VPS, and so I decided to write this little guide to refresh
my memory on how to set up OpenVPN.&lt;&#x2F;p&gt;
&lt;p&gt;Before we begin to set up our VPN, we need to install OpenVPN. I am using Debian
Stretch, so your install process may differ depending on your distro.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# apt-get install openvpn easy-rsa
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;configuring-openvpn&quot;&gt;Configuring OpenVPN&lt;&#x2F;h2&gt;
&lt;p&gt;After installing the necessary packages, we proceed to configure OpenVPN. First
we need to extract the sample OpenVPN server configuration file to &#x2F;etc&#x2F;openvpn&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# gunzip -c &#x2F;usr&#x2F;share&#x2F;doc&#x2F;openvpn&#x2F;examples&#x2F;sample-config-files&#x2F;server.conf.gz &amp;gt; &#x2F;etc&#x2F;openvpn&#x2F;server.conf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we proceed to edit it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# vim &#x2F;etc&#x2F;openvpn&#x2F;server.conf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Inside we will make changes to basically use higher-level encryption, forward
web traffic to destination, prevent DNS leaking, and set up permissions.&lt;&#x2F;p&gt;
&lt;p&gt;First we make sure that we are using 2048 bit-length keys instead of 1024. In my
case it was already set to 2048 bit by default, however, the first time that I
set up OpenVPN the default was 1024, so find this line&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;dh dh2048.pem
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If instead you see &quot;dh1024.pem&quot; change it so that it is like in this example.&lt;&#x2F;p&gt;
&lt;p&gt;Next we make sure to redirect all traffic to its proper destination. Find this
line&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;push &amp;quot;redirect-gateway def1 bypass-dhcp&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If it has a semicolon (;) at the beginning, remove it so that it is uncommented.&lt;&#x2F;p&gt;
&lt;p&gt;Now we will tell OpenVPN to use OpenDNS for DNS resolution. This will help
prevent DNS requests from leaking outside of the VPN connection.&lt;&#x2F;p&gt;
&lt;p&gt;Immediately after the previous setting, you will see a block of comments
followed by two commented lines&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;push &amp;quot;dhcp-option DNS 208.67.222.222&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;push &amp;quot;dhcp-option DNS 208.67.220.220&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As previously, just remove the semicolon character from the beginning of the
line.&lt;&#x2F;p&gt;
&lt;p&gt;Next we should comment the next line with a # or ; character. It is supposed to
be used as an extra security measure especially against DoS attacks, however, we
don&#x27;t really need it&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;tls-auth ta.key 0 # This file is secret
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you really want to leave that on, you will need to generate it&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;openvpn&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; --genkey --secret&lt;&#x2F;span&gt;&lt;span&gt; ta.key
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And last but not least in our server.conf file, we need to adjust permissions.
Find and uncomment these lines&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user nobody
&lt;&#x2F;span&gt;&lt;span&gt;group nogroup
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This way OpenVPN doesn&#x27;t run as the root user. And we don&#x27;t want any random
program wildly running as root, especially ones that are exposed to the
interwebz, no sir we don&#x27;t ( ͡° ͜ʖ ͡°).&lt;&#x2F;p&gt;
&lt;p&gt;After having made all the needed changes, just write them and close the editor.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;configuring-network-and-firewall&quot;&gt;Configuring network and firewall&lt;&#x2F;h2&gt;
&lt;p&gt;We need to enable packet forwarding, otherwise our traffic will not leave the
server.&lt;&#x2F;p&gt;
&lt;p&gt;So that we don&#x27;t have to reboot our server (let&#x27;s leave all that rebooting to
windows systems), we can enable it on runtime by running the following command&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# sysctl net.ipv4.ip_forward=1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, we need to make this change permanent as well, so we open the following
file&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# vim &#x2F;etc&#x2F;sysctl.conf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And uncomment the following line by removing the hash character (#) at the
beginning of the line&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;net.ipv4.ip_forward&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Save your changes and close the editor.&lt;&#x2F;p&gt;
&lt;p&gt;Now we need to properly set up our firewall. Personally I use ufw as front-end
to iptables, since it is pretty easy to set up and use (as its name suggests,
uncomplicated firewall). If you don&#x27;t have it installed yet, you can go ahead
and run&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# apt-get install ufw
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By default ufw denies all incoming connections and allow all outgoing. Those
defaults are fine for my case, some might prefer to deny all outgoing
connections by default, some riskier guys (or gals) might prefer to allow all by
default (however, you wouldn&#x27;t have unprotected fun time with just any partner,
now would you?( ͡° ͜ʖ ͡°)), however explaining all the details about ufw is out of
the scope of this tutorial, but I invite you use your duckduckgo-fu if you&#x27;re
interested in learning more about ufw.&lt;&#x2F;p&gt;
&lt;p&gt;Now, as ufw denies all incoming connections by default, we need to configure it
so that we don&#x27;t get locked out of our server. If you use the standard ssh port,
just run the following command&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# ufw allow ssh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ufw comes with some presets for the most common services, so that in fact allows
connections from port 22 over tcp. If you, like me, prefer to use another port
for SSH, you need to specify the port and protocol manually, so, if say, you
connect to SSH over port 3333, you would run&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# ufw allow 3333&#x2F;tcp
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(Of course that is not the actual port I myself use for ssh, so don&#x27;t even try
(That is however not an open invitation to try and guess my SSH port and hack
yourself into my server (seriously, please don&#x27;t hack me ´༎ຶ ͜ʖ ༎ຶ ))).&lt;&#x2F;p&gt;
&lt;p&gt;In this tutorial we will be using OpenVPN on port 1194 over UDP, so we must
allow it&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# ufw allow 1194&#x2F;udp
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we need to set ufw&#x27;s forwarding policy, so we open the primary
configuration file&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# vim &#x2F;etc&#x2F;default&#x2F;ufw
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Modify the following line&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;DEFAULT_FORWARD_POLICY=&amp;quot;DROP&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So that it looks like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;DEFAULT_FORWARD_POLICY=&amp;quot;ACCEPT&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Save and exit.&lt;&#x2F;p&gt;
&lt;p&gt;Open this file&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# vim &#x2F;etc&#x2F;ufw&#x2F;before.rules
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And add the rules for OpenVPN somewhere after the first block of comments&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# START OPENVPN RULES
&lt;&#x2F;span&gt;&lt;span&gt;# NAT table rules
&lt;&#x2F;span&gt;&lt;span&gt;*nat
&lt;&#x2F;span&gt;&lt;span&gt;:POSTROUTING ACCEPT [0:0]
&lt;&#x2F;span&gt;&lt;span&gt;# Allow traffic from OpenVPN client to eth0
&lt;&#x2F;span&gt;&lt;span&gt;-A POSTROUTING -s 10.8.0.0&#x2F;8 -o eth0 -j MASQUERADE
&lt;&#x2F;span&gt;&lt;span&gt;COMMIT
&lt;&#x2F;span&gt;&lt;span&gt;# END OPENVPN RULES
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once more, save and exit.&lt;&#x2F;p&gt;
&lt;p&gt;Now we can safely enable ufw&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# ufw enable
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will say something about disrupting current SSH connections, however, since
we just added the needed rules for SSH we can go ahead and answer y.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;configuring-the-certificate-authority&quot;&gt;Configuring the Certificate Authority&lt;&#x2F;h2&gt;
&lt;p&gt;Now we are going to setup our own CA. This is crucial since OpenVPN encrypts
traffic (what use is a VPN that doesn&#x27;t encrypt traffic?)&lt;&#x2F;p&gt;
&lt;p&gt;First we need to copy the RSA generation scripts&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# cp -r &#x2F;usr&#x2F;share&#x2F;easy-rsa&#x2F; &#x2F;etc&#x2F;openvpn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we create a directory to house our keys&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# mkdir &#x2F;etc&#x2F;openvpn&#x2F;easy-rsa&#x2F;keys
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we open the variables files&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# vim &#x2F;etc&#x2F;openvpn&#x2F;easy-rsa&#x2F;vars
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And modify these lines according to our needs&#x2F;preferences (they are not that
really important)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# These are the default values for fields
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# which will be placed in the certificate.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Don&amp;#39;t leave any of these fields blank.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;KEY_COUNTRY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;US&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;KEY_PROVINCE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;CA&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;KEY_CITY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;SanFrancisco&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;KEY_ORG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Fort-Funston&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;KEY_EMAIL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;me@myhost.mydomain&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;KEY_OU&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;MyOrganizationalUnit&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, in the same file, we need to change the name of the key. For simplicity&#x27;s
sake we will use the name &quot;server&quot;, since that&#x27;s the name that OpenVPN uses to
reference the .key and .crt files by default. If you decide to use a different
name, you will need to modify the OpenVPN configuration files that reference the
aformentioned files.&lt;&#x2F;p&gt;
&lt;p&gt;So change this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# X509 Subject Field
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;KEY_NAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;EasyRSA&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Into this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# X509 Subject Field
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;KEY_NAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;server&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Save and exit.&lt;&#x2F;p&gt;
&lt;p&gt;Next we will use OpenSSL to generate the Diffie-Helman parameters. Grab a cup of
tea, take a seat, it might take some minutes&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# openssl dhparam -out &#x2F;etc&#x2F;openvpn&#x2F;dh2048.pem 2048
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that our certificate is ready, it&#x27;s time to generate a key. For that, we
first switch into the easy-rsa folder&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# cd &#x2F;etc&#x2F;openvpn&#x2F;easy-rsa
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we start setting up the CA. We first, need to initialize the Public Key
Infrastructure (PKI). For that we need to source the vars file&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# . .&#x2F;var
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you get something like this in your output&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;  No &#x2F;etc&#x2F;openvpn&#x2F;easy-rsa&#x2F;openssl.cnf file could be found
&lt;&#x2F;span&gt;&lt;span&gt;  Further invocations will fail
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Your .cnf might have a different name (due to differing versions of OpenSSL).
Just copy it like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# cp openssl-*.cnf openssl.cnf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And source the vars file one more time.&lt;&#x2F;p&gt;
&lt;p&gt;After sourcing the vars file, it will give us a warning about removing some
files. Don&#x27;t sweat it, it&#x27;s fine, since right now that folder is empty. So we go
ahead and clear any and all keys that might interfere with out setup&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# .&#x2F;clean-all
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, we can go ahead and build our CA using the following command&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# .&#x2F;build-ca
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can skip through each prompt since we set up that info previously inside the
vars file. The CA is now ready to go.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generating-a-certificate-and-key-for-our-server&quot;&gt;Generating a certificate and key for our server&lt;&#x2F;h2&gt;
&lt;p&gt;Now we can proceed to actually setting up and launching OpenVPN.&lt;&#x2F;p&gt;
&lt;p&gt;While still on the easy-rsa folder, we input this command&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# .&#x2F;build-key-server server
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;server is the name of the key that we set up earlier in the vars file. We can go
ahead, and as earlier leave the defaults which we configured in the vars file.&lt;&#x2F;p&gt;
&lt;p&gt;Upon reaching these prompts&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;A challenge password []:
&lt;&#x2F;span&gt;&lt;span&gt;An optional company name []:
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just press enter for both. We won&#x27;t be needing them for this setup.&lt;&#x2F;p&gt;
&lt;p&gt;The last two entries require a y answer&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;Sign the certificate? [y&#x2F;n]
&lt;&#x2F;span&gt;&lt;span&gt;1 out of 1 certificate requests certified, commit? [y&#x2F;n]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that our server certificate and key are ready, we need to copy them over to
&#x2F;etc&#x2F;openvpn, since that the directory in which OpenVPN will be looking for them&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# cp &#x2F;etc&#x2F;openvpn&#x2F;easy-rsa&#x2F;keys&#x2F;{server.crt,server.key,ca.crt} &#x2F;etc&#x2F;openvpn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we can start OpenVPN&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# systemctl start openvpn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can check if it launched correctly by running&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# systemctl status openvpn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It should say something like &quot;Active: active (exited) since...&quot; then,
congratulations! OpenVPN is now running in your server. If it says otherwise,
maybe something like &quot;inactive (dead)...&quot;, you might to check the log file
&quot;&#x2F;var&#x2F;log&#x2F;syslog&quot; for errors.&lt;&#x2F;p&gt;
&lt;p&gt;If all is fine and dandy, you can enable the OpenVPN service so that it
automatically starts on each reboot&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# systemctl enable openvpn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;generating-certificates-keys-for-clients&quot;&gt;Generating certificates keys for clients&lt;&#x2F;h2&gt;
&lt;p&gt;Ideally each client that needs to connect to the VPN should have their own
unique certificate and key. Actually, by default, OpenVPN doesn&#x27;t allow
simultaneous connections using the same certificate.&lt;&#x2F;p&gt;
&lt;p&gt;Because of that you will need to repeat the steps in this section for each
device that you wish to allow to connect to your VPN, just changing the name
&quot;desktop&quot; below, to something different like &quot;laptop&quot; or &quot;phone&quot;. This way you
can also later deactivate a specific device&#x2F;client from accessing if needed be.&lt;&#x2F;p&gt;
&lt;p&gt;I will start by building the key and certificate for my desktop computer, so I
will be using the &quot;desktop&quot; name as an example. We still should be in our
easy-rsa directory&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# .&#x2F;build-key desktop
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once more, as with the server&#x27;s cert and key, we will asked about some info
which we set on the vars, so we should skip all that by pressing enter
(including setting the passwords). Just press y both times at the end to
confirm.&lt;&#x2F;p&gt;
&lt;p&gt;Now we need the sample profile to the keys folder. We need to change its
extension to ovpn, since that will be the file that OpenVPN will use on each
device to automatically set the profile to connect to our VPN server&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# cp &#x2F;usr&#x2F;share&#x2F;doc&#x2F;openvpn&#x2F;examples&#x2F;sample-config-files&#x2F;client.conf &#x2F;etc&#x2F;openvpn&#x2F;easy-rsa&#x2F;keys&#x2F;client.ovpn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The name of this file doesn&#x27;t need to be related to our client&#x27;s cert and key
filenames, we can actually name to something that will describe our VPN, since
that will be the name that OpenVPN will be pick up by default in our client
device for our profile. So you can name it &quot;work.ovpn&quot; or maybe something more
rich like &quot;muhfreedumbs.ovpn&quot;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# mv keys&#x2F;client.ovpn keys&#x2F;muhfreedumbs.ovpn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that we need to make some modifications to our ovpn file, so open it up&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# vim keys&#x2F;muhfreedumbs.ovpn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And edit the line starting with remote with your server&#x27;s ip address&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;remote your.ip.address.here 1194
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And if you chose to leave out the &quot;ta.key&quot; file protection option, don&#x27;t forget
to comment this line&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;tls-auth ta.key 0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we find these two lines and uncomment them (remove the ; character at the
beginning of each line)&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;user nobody
&lt;&#x2F;span&gt;&lt;span&gt;group nogroup
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s it. All that&#x27;s left is to copy the client key and certificate, and the
ovpn file over to our device. First we need to copy them to another folder that
is available to our standard (non-root) user on the server for reading, since it
is not a good idea to have root login enabled on SSH. For example, we could
create a &quot;vpnkeys&quot; folder in our user&#x27;s home directory&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; mkdir &#x2F;home&#x2F;yaroslav&#x2F;vpnkeys
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then copy the need files over to that folder&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# cp &#x2F;etc&#x2F;openvpn&#x2F;easy-rsa&#x2F;keys&#x2F;{desktop.key,desktop.crt,muhfreedumbs.ovpn} &#x2F;home&#x2F;yaroslav&#x2F;vpnkeys&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is one more file that we need to copy, the server&#x27;s certificate&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# cp &#x2F;etc&#x2F;openvpn&#x2F;ca.crt &#x2F;home&#x2F;yaroslav&#x2F;vpnkeys&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you previously also left the secret &quot;ta.key&quot; file enabled and generated it,
you should copy that too.&lt;&#x2F;p&gt;
&lt;p&gt;Note that the &quot;ca.crt&quot; and the ovpn files will be the same for all devices. If
you wish to create a new key&#x2F;cert pair for another device&#x2F;client, you DO NOT
need to create a new ovpn file, just run the &quot;.&#x2F;build-key clientkeyname&quot; command
as before and copy the same old ovpn and ca.crt file along with client key and
cert to your other device.&lt;&#x2F;p&gt;
&lt;p&gt;Now we need to actually copy the keys to our device. You can use rsync or scp
for that. For example, I will be using scp to copy them to my Keys folder&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; scp&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -P&lt;&#x2F;span&gt;&lt;span&gt; portno&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -r&lt;&#x2F;span&gt;&lt;span&gt; yaroslav@ipaddressorurl:&#x2F;home&#x2F;yaroslav&#x2F;vpnkeys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;Keys&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you need to use your VPN on your mobile device, just copy them first to your
computer through SSH, and then transfer them over to your mobile device.&lt;&#x2F;p&gt;
&lt;p&gt;After transferring them to the device, you should delete the keys from the home
directory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Now that all is setup on the server side of things, you can go ahead and add
your VPN profile on your device. This process will vary greatly from device to
device.&lt;&#x2F;p&gt;
&lt;p&gt;On most Linux distros&#x2F;DEs, for example, you would go to your network manager,
and select &quot;Configure VPN...&quot; or something like that. Then, a window with a list
of (VPN) connections will appear, and you should be able to add your profile by
clicking on the plus (+) button. After another window like this should pop up&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;your-own-vpn&#x2F;vpndialog.png&quot; alt=&quot;VPN dialog&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You should select the option that says &quot;Import a saved VPN configuration...&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Note that the &quot;openvpn&quot; and &quot;networkmanager-openvpn&quot; packages should be
installed in your (client) system.&lt;&#x2F;p&gt;
&lt;p&gt;Once you have connected to your VPN, you can head over to
&lt;a href=&quot;https:&#x2F;&#x2F;dnsleaktest.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;dnsleaktest.com&#x2F;&lt;&#x2F;a&gt; to check your connectivity.&lt;&#x2F;p&gt;
&lt;p&gt;Now you can more safely and securely browse the interwebz, and be sure that no
third-party VPN company is logging your activity.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Some thoughts on web design</title>
		<published>2018-10-20T02:25:00+00:00</published>
		<updated>2018-10-20T02:25:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/thoughts-on-web-design/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/thoughts-on-web-design/</id>
		<content type="html">&lt;p&gt;I am no designer by any means, I mostly prefer to deal with the technical side
of things. However I do appreciate when things aren&#x27;t an eyesore, and most
importantly regarding technology, when the design doesn&#x27;t get in the way. That
is, I value more UX, than an overtly designed UI.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Early on websites were designed to just contain information, things like text
and images, without any of the fancy things that come with today&#x27;s websites.
Nowadays it seems almost like a must that a website should have some kind of
interactivity, even if it doesn&#x27;t add any actual value to the website.&lt;&#x2F;p&gt;
&lt;p&gt;I am not trying to say that websites should stay the same static things that
they were in the past, rather, that a lot of bloat has been added to them in an
attempt to make them more &quot;appealing&quot; and interactive, which is not a bad thing
in and of itself.&lt;&#x2F;p&gt;
&lt;p&gt;However, that trend has spawned a lot of bloated websites with unnecessary or
even annoying gimmicks. Gimmicks like menus that open up automatically blocking
the view of what you are reading, and assume that you actually need it at the
moment. Or the worst offender, autoplaying videos.&lt;&#x2F;p&gt;
&lt;p&gt;Setting aside my rants about the modern offenses of design and UX in web
development, I want to focus on a couple of issues.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;typography-readability&quot;&gt;Typography&#x2F;Readability&lt;&#x2F;h2&gt;
&lt;p&gt;I have started to notice lately that a great deal of
websites tend to neglect what I think is one of the most important aspects in a
good user experience (maybe except for media sites like youtube), and that is
the text itself.&lt;&#x2F;p&gt;
&lt;p&gt;The people who design these sites seem to pay too much attention to the overall
style of the site and its elements, but don&#x27;t seem to care about the actual
legibility of them. One might think that font type and size should be enough,
but those are far from the only important aspects to consider for comfortable
reading. Line length and spacing are also key aspects, and might be even more
important than the font you choose (just don&#x27;t choose some quirky font like
Comic Sans, for your readers sanity&#x27;s sake).&lt;&#x2F;p&gt;
&lt;p&gt;I came to the realization that line length is a really important aspect for a
comfortable read, after having worked some time with LaTeX and wondering why it
always defaulted to the same line length. I always noticed that documents
produced in LaTeX were more pleasant to read than, for example, Word documents,
and it was not only the font.&lt;&#x2F;p&gt;
&lt;p&gt;So after some reading on the internet about the choices of the default styles
for LaTeX, I realized how important line length is. I now understood why even
PDFs were more pleasant to read than your average website.&lt;&#x2F;p&gt;
&lt;p&gt;Consider a book. Have you ever read a book whose line length was more than 80
characters? If so, that&#x27;s a terrible book.&lt;&#x2F;p&gt;
&lt;p&gt;There seems to be some consensus that an optimal line length should be between
50-75 characters, spaces included (right now my blog&#x27;s articles are at about 80
characters, so there&#x27;s room for improvement).&lt;&#x2F;p&gt;
&lt;p&gt;If the line is too narrow, it breaks the reader&#x27;s rhythm, and stresses them. If
it is too wide, the read will have a harder time focusing on the text, it will
be harder to gauge where the line ends and the next begin, and the reader&#x27;s eyes
will end up moving more horizontally, also stressing the reader in the end.&lt;&#x2F;p&gt;
&lt;p&gt;A lot of websites tend to present the text in lines too long for comfortable
reading. That factor ends up contributing in more readers skimming through text
and not paying much attention to what has been written.&lt;&#x2F;p&gt;
&lt;p&gt;One more thing would be line height. I&#x27;ve noticed that many websites tend to use
most of the default styles for text, and sometimes the line height ends up being
too small for the font used and the lines of text being crammed. It&#x27;s not as bad
as with the line length, but it is a problem present in some websites.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bloat&quot;&gt;Bloat&lt;&#x2F;h2&gt;
&lt;p&gt;Oh boy, there&#x27;s a lot that can be said about bloat on modern websites.
I&#x27;ll try to keep it short. I&#x27;ll begin by writing about some &quot;addons&quot; that end up
making sites heavier than they should.&lt;&#x2F;p&gt;
&lt;p&gt;I feel like for most use cases JQuery is a really unnecessary thing to use. Most
website don&#x27;t need half the features that JQuery provides, and most of its
features are just &quot;shortcuts&quot; that JS already offers by default. I mean, if
you&#x27;re using JQuery, most of the time, you&#x27;re being lazy. JQuery makes your site
unnecessarily heavier, although if your site is already JS-heavy, and the focus
of your site is actually on providing some specific functionality, JQuery can be
a great tool.&lt;&#x2F;p&gt;
&lt;p&gt;Another thing that bloats sites, are CSS frameworks (e.g. Bootstrap). They can
make life easier when building templates for your sites, but most of the time,
as is the case with JQuery, you&#x27;re not going to use half the features it
provides. In this case, it can get worse, since you will most probably end up
overriding a great deal of the default style provided with the framework anyway,
especially if you don&#x27;t want your site to look generic.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, on the topic of bloat, is feature and visual bloat.&lt;&#x2F;p&gt;
&lt;p&gt;The biggest offenders I have found to be news sites, especially those kinds of
&quot;specialized&quot; magazine type of sites. You enter the site to read the article,
and most of your screen is occupied by ads, useless images and links to other
articles and associated websites that distract you from your reading.&lt;&#x2F;p&gt;
&lt;p&gt;And don&#x27;t get me started on the autoplaying videos (I&#x27;m looking at you CNN,
although I don&#x27;t even know why I bother to read their &lt;del&gt;biased bullshit&lt;&#x2F;del&gt;
articles).  If I opened up an article, I want to read. READ, not watch or listen
some dude babbling about what I&#x27;m intending on reading. If I wanted to watch a
video, I would have gone to the videos section of the site, or to YouTube.&lt;&#x2F;p&gt;
&lt;p&gt;Might be just my humble opinion, but when I am reading, I like to see only the
text in front of me, with maybe some links to the sides or top&#x2F;bottom, to help
me navigate, and maybe some images relevant to what I am reading.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion-final-words&quot;&gt;Conclusion&#x2F;Final words&lt;&#x2F;h2&gt;
&lt;p&gt;Keep those lines at a sane width, let your lines and characters breathe with a
little bit of space, and maybe up your font size a bit if you notice you start
squinting when trying to read.&lt;&#x2F;p&gt;
&lt;p&gt;Fluid design doesn&#x27;t mean that the container where your text is should occupy
the entire width of your screen.&lt;&#x2F;p&gt;
&lt;p&gt;Make beautiful, but lightweight (in bytes, and visually) websites, that are
comfortable to read, and your readers will thank you.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;some-links-that-might-be-of-interest&quot;&gt;Some links that might be of interest:&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;baymard.com&#x2F;blog&#x2F;line-length-readability&quot;&gt;https:&#x2F;&#x2F;baymard.com&#x2F;blog&#x2F;line-length-readability&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.paulolyslager.com&#x2F;optimal-text-layout-line-length&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.paulolyslager.com&#x2F;optimal-text-layout-line-length&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;bettermotherfuckingwebsite.com&#x2F;&quot;&gt;http:&#x2F;&#x2F;bettermotherfuckingwebsite.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>New w3blog release, version 0.5</title>
		<published>2018-10-10T12:04:00+00:00</published>
		<updated>2018-10-10T12:04:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/w3blog-v05-release/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/w3blog-v05-release/</id>
		<content type="html">&lt;p&gt;After some months without much free time, I finally could sit down a week ago
and start working on an update to my blog engine that had been sitting on my
to-do list for quite some time. This update brings improvements and new
features to w3blog.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;First of all, bloat was removed on the front end (client) side of things. I
got rid of Bootstrap, and JQuery, and rewrote the default CSS sheet. The
default look of the engine is actually pleasant to look at, the css sheet
weighs only 5.6K unminified (vs 138K of minified bootstrap&#x27;s css), and of
course weight has also been slimmed down by removing JQuery (it was only
really needed by bootstrap).&lt;&#x2F;p&gt;
&lt;p&gt;v0.4 default look&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-v05-release&#x2F;v04.png&quot; alt=&quot;v0.4&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;v0.5 default look&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-v05-release&#x2F;v05.png&quot; alt=&quot;v0.5&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Speaking about improvements, comments now have a date of publishing. Really not
sure how I overlooked such a thing for so long.&lt;&#x2F;p&gt;
&lt;p&gt;The new features are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Dynamic loading of posts on the main page, and category and archive pages. If
you turn on this feature, instead of getting the traditional pagination
buttons at the end of the page, you get a button to load the next batch of
posts through AJAX, so that it doesn&#x27;t load a whole new page. You turn this
by adding &lt;code&gt;&#x27;dynamic_load&#x27;: True&lt;&#x2F;code&gt; to &lt;code&gt;WEBLOG_SETTINGS&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Infinite scroll for dynamic loading. When this and dynamic loading are
active, after scrolling to the bottom of the page (index, category page,
archive page), the next batch of posts are loaded automatically through AJAX.
Turn on dynamic loading (see above) and add &lt;code&gt;&#x27;infinite_load&#x27;: True&lt;&#x2F;code&gt; to
&lt;code&gt;WEBLOG_SETTINGS&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Floating sidebar. To turn this feature on, you add &lt;code&gt;&#x27;floating_sidebar&#x27;: True&lt;&#x2F;code&gt;
to &lt;code&gt;WEBLOG_SETTINGS&lt;&#x2F;code&gt;. What this does, is make the sidebar float next to the
content container after scrolling past the navbar and breadcrumb bar.&lt;&#x2F;li&gt;
&lt;li&gt;These are basically all of the changes in this new release. If you happen to
already be using w3blog and are using a custom css sheet, you will need to
redo your css since the templates changed a bit since version 0.4, mainly the
html&#x2F;css classes used. You will also need to make migrations and migrate them
to the database.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I had plans for other features for this release, but I decided to postpone them
for now. One of them was a way to add custom elements&#x2F;html to the sidebar
without having to modify w3blog templates. Unfortunately I didn&#x27;t find a sane
way of doing this.&lt;&#x2F;p&gt;
&lt;p&gt;If you have any issues with w3blog, or maybe even suggestions, the first option
would be to open an issue on its Github page, if you don&#x27;t have a Github
account (and don&#x27;t want to create one), you can write me an email at
&lt;a href=&quot;mailto:contact@yaroslavps.com&quot;&gt;contact@yaroslavps.com&lt;&#x2F;a&gt;. However, if you are
using one of the big email providers (e.g. outlook or gmail), my response could
be blocked by your provider.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Yaroslav-95&#x2F;w3blog&quot;&gt;w3blog&#x27;s GitHub page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Free and easy SSL with Let&#x27;s Encrypt</title>
		<published>2018-08-12T22:28:00+00:00</published>
		<updated>2018-08-12T22:28:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/ssl-with-lets-encrypt/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/ssl-with-lets-encrypt/</id>
		<content type="html">&lt;p&gt;We all know that in this day and age security is an important factor when
developing sites, and not only. Also let&#x27;s not forget about that sweet Google
SEO which rewards sites which use https instead of the old http (Although I
couldn&#x27;t care less about Google, however some people I might work with do, and
I bet most of you reading also care).&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;You might want to add SSL to your site, but, you might think, those SSL certs cost
money, and they ain&#x27;t exactly cheap. And that&#x27;s where you are wrong my friend
(unless you already knew about Let&#x27;s Encrypt and are only reading this to learn
how to generate a certificate, in that case I apologize for the cringe
introduction).&lt;&#x2F;p&gt;
&lt;p&gt;Here I will be detailing the steps to acquire an SSL certificate with Let&#x27;s
Encrypt using Certbot, with nginx. I will be installing Certbot on a Debian
Stretch server, so you might need to input a different command depending on the
distro or OS you are using.&lt;&#x2F;p&gt;
&lt;p&gt;First we need to install Certbot&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# apt-get install certbot
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Before we can install the certificates, we need to configure nginx for
certficate installation and renewal. We can set the default server
configuration on nginx for that. We need to do this so that Let&#x27;s Encrypt&#x27;s
server can read the challenge generated by Certbot and verify that we indeed
own the domain(s) for which we want to make the certificate.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;        listen 80 default_server;
&lt;&#x2F;span&gt;&lt;span&gt;        listen [::]:80 default_server;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        server_name _;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        # This is so that Let&amp;#39;s Encrypt can look for the challenge
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F;.well-known&#x2F;acme-challenge&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                root &#x2F;var&#x2F;www&#x2F;html&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;                default_type text&#x2F;plain;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        # The rest of your configuration...
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once we have edited the default configuration file, we need to restart nginx.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# sudo systemctl restart nginx
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that we can get started installing the certificate. I wanted to get a
certificate for more than subdomain, so I added them using the -d flag to my
list of arguments like in the following example&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# certbot certonly --webroot -w &#x2F;var&#x2F;www&#x2F;html -d www.example.com -d example.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will ask your email for renew notifications, although certbot should renew
your certificates automatically before expiration.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s it, you should already have the new certificate and keys on your server.
Now you can go ahead and configure nginx to accept https connections and
redirect plain old insecure http requests to https. You should also put the
correct path for your certificate and public key under &lt;code&gt;ssl_certificate&lt;&#x2F;code&gt; and
&lt;code&gt;ssl_certificate_key&lt;&#x2F;code&gt; respectively.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;        listen 80;
&lt;&#x2F;span&gt;&lt;span&gt;        listen [::]:80;
&lt;&#x2F;span&gt;&lt;span&gt;        server_name www.example.com;
&lt;&#x2F;span&gt;&lt;span&gt;        return 301 https:&#x2F;&#x2F;$host$request_uri;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;        listen 443 ssl;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        server_name www.example.com;
&lt;&#x2F;span&gt;&lt;span&gt;        ssl_certificate &#x2F;etc&#x2F;letsencrypt&#x2F;live&#x2F;www.example.com&#x2F;fullchain.pem;
&lt;&#x2F;span&gt;&lt;span&gt;        ssl_certificate_key &#x2F;path&#x2F;to&#x2F;key&#x2F;www.example.com&#x2F;privkey.pem;
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F;static&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                alias &#x2F;home&#x2F;webuser&#x2F;mysite&#x2F;static&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F;media&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                alias &#x2F;home&#x2F;webuser&#x2F;mysite&#x2F;media&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_set_header Host $http_host;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_redirect off;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_pass http:&#x2F;&#x2F;127.0.0.1:8001;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The downside of automatically redirecting http requests to https is that old
browsers that don&#x27;t support https won&#x27;t be able to open your site. But come on,
it&#x27;s 2018, who cares about 10+ year old software. Even if you are running
really old hardware there definitely is some modern free software that runs on
that hardware.&lt;&#x2F;p&gt;
&lt;p&gt;For more information on Certbot:
&lt;a href=&quot;https:&#x2F;&#x2F;certbot.eff.org&#x2F;docs&#x2F;using.html&quot;&gt;https:&#x2F;&#x2F;certbot.eff.org&#x2F;docs&#x2F;using.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Update (2018&#x2F;11&#x2F;02): Sometime in 2018 Let&#x27;s Encrypt added the possibility to
generate a wildcard SSL certificate (e.g. *.example.com).&lt;&#x2F;p&gt;
&lt;p&gt;To generate such a certificate we will need to download certbot from the git
repository&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; git clone https:&#x2F;&#x2F;github.com&#x2F;certbot&#x2F;certbot.git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we cd into certbot and run&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;certbot-auto certonly&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; --manual &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;--preferred-challenges=dns \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;--email email@example.com \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;--server https:&#x2F;&#x2F;acme-v02.api.letsencrypt.org&#x2F;directory \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;--agree-tos \
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;-d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.example.com
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For this you will need to add a TXT record to the DNS settings of your domain,
since this only works using the dns challenge. Before pressing enter make sure
that your record has been deployed.&lt;&#x2F;p&gt;
&lt;p&gt;Do keep in mind that it&#x27;s not currently possible to renew this kind of
certificate automatically.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>How to break pip, and how to repair it...</title>
		<published>2018-08-03T22:00:00+00:00</published>
		<updated>2018-08-03T22:00:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/how-to-break-and-repair-pip/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/how-to-break-and-repair-pip/</id>
		<content type="html">&lt;p&gt;Sometimes a program may suggest to you something, and you may following said
program&#x27;s suggestion, because, why not, you trust the devs because they&#x27;ve done
an amazing job developing the program, and heck, they should know what they are
doing with their tools.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;With pip, this does not seem to be the case however. I&#x27;ve come across this
issue on my laptop and desktop computers running Manjaro, and while fixed it on
my laptop, I forgot how to fix it by the time I encountered on my desktop. The
problem: pip refuses to collect a package while trying to install any package
system wide (e.g. pywal), exiting with an exception like &#x27;ModuleNotFoundError&#x27;
or something similar.&lt;&#x2F;p&gt;
&lt;p&gt;First, I&#x27;ll write down what NOT to do to avoid getting this error.&lt;&#x2F;p&gt;
&lt;p&gt;You may get a message like this when after installing a package with pip&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;You&lt;&#x2F;span&gt;&lt;span&gt; are using pip version x.x.x, however version x.x is available.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;You&lt;&#x2F;span&gt;&lt;span&gt; should consider upgrading via the &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;pip install --upgrade pip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; command.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you get the following while NOT using a virtual environment, don&#x27;t pay
attention to it. Don&#x27;t even look at it. Just ignore it. I didn&#x27;t, and now I am
writing a post about how to fix the mess that it causes because of following
that seemingly innocent and well-intended advice. At least not if you are using
an Arch-based distribution, don&#x27;t really know about how this is managed in
other distributions, since I don&#x27;t recall having this problem when using
Debian.&lt;&#x2F;p&gt;
&lt;p&gt;Now, if you are using a virtual environment, you obviously can and should
upgrade pip this way. However, system-wide, your package manager (pacman)
should take care of upgrading pip along with your other packages when you
upgrade your system (pacman -Syu).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-fix&quot;&gt;The fix&lt;&#x2F;h2&gt;
&lt;p&gt;If you unfortunately, like me, already ran the upgrade through pip, you should
first delete some files, by running this command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo rm&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -rf&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;usr&#x2F;lib&#x2F;python3.6&#x2F;site-packages&#x2F;pip &#x2F;usr&#x2F;lib&#x2F;python3.6&#x2F;site-packages&#x2F;pkg_resources
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, you should reinstall pip and setup tools:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo pacman&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -S&lt;&#x2F;span&gt;&lt;span&gt; python-setuptools python-pip
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And that&#x27;s it! Your pip should now be as good as new.&lt;&#x2F;p&gt;
&lt;p&gt;I found the solution in this forum thread: &lt;a href=&quot;https:&#x2F;&#x2F;bbs.archlinux.org&#x2F;viewtopic.php?id=237451&quot;&gt;https:&#x2F;&#x2F;bbs.archlinux.org&#x2F;viewtopic.php?id=237451&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>w3blog, a simple blog engine</title>
		<published>2018-07-23T02:05:00+00:00</published>
		<updated>2018-07-23T02:05:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/w3blog-blog-engine/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/w3blog-blog-engine/</id>
		<content type="html">&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;preview.png&quot; alt=&quot;w3blog&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this post I will be explaining how to use my blog engine for the Django
framework, w3blog.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;first-an-introduction&quot;&gt;First, an introduction&lt;&#x2F;h2&gt;
&lt;p&gt;I decided to create my own blog engine because I didn&#x27;t find one for Django
that satisfied my needs. That is, I wanted a simple to setup, but customizable
blog engine that offered multilingual capabilities since I wanted to write my
blog in three different languages (English, Spanish and Russian). I wanted to
be able to write posts in different languages and make use of Django&#x27;s built-in
localization engine, so that if user&#x27;s locale is, for example, Spanish, so that
they would immediately see the posts in Spanish, if they are already translated
to Spanish.&lt;&#x2F;p&gt;
&lt;p&gt;The following is a short list of features of w3blog:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Users can post anonymous comments, if enabled&lt;&#x2F;li&gt;
&lt;li&gt;Allow only registered users to post comments through Django&#x27;s built-in
authentication engine, if enabled&lt;&#x2F;li&gt;
&lt;li&gt;Can use own base template&lt;&#x2F;li&gt;
&lt;li&gt;RSS&lt;&#x2F;li&gt;
&lt;li&gt;Turn on or off the sidebar, and chose to show categories, archive list, none,
or both in the sidebar&lt;&#x2F;li&gt;
&lt;li&gt;Show or hide the author of the post, and whether it shows the author&#x27;s name
or username&lt;&#x2F;li&gt;
&lt;li&gt;Enable or disable multilingual features&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These are features available as of the writing of this post (v0.4.2). In the
next version (v0.5.x) I plan on adding the ability to further customize the
sidebar without having to modify the internal templates of the app.&lt;&#x2F;p&gt;
&lt;p&gt;I will be showing you further down below how to setup the engine to customize these features.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h2&gt;
&lt;p&gt;First of all, you need to install a couple of python modules with pip. w3blog
itself, and django-summernote. Check out https:&#x2F;&#x2F;summernote.org&#x2F; for more
information about it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; pip install w3blog django-summernote
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After installing them, we need to add to the settings.py list of installed apps&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;INSTALLED_APPS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;django_summernote&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;weblog&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And add the following urls to our project&#x27;s main urls.py&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;^&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;blog&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;include&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;weblog.urls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;^&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;summernote&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;include&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;django_summernote.urls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So if we now run our development server and go to our browser to the respective
link, we should now see something similar to the following&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;first_launch.jpg&quot; alt=&quot;w3blog home page on first launch&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After creating a django super user and going to the admin, we can now see a
weblog section with two models: Blog posts and Categories.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;admin1.png&quot; alt=&quot;Admin panel on first launch&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can add a category&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;add_category.png&quot; alt=&quot;Adding a category&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We could try and add a post now&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;add_post.png&quot; alt=&quot;Adding a post&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Chose a slug (the portion of the url for the post), the categor(y&#x2F;ies), whether
we want it to be available to the reader after saving (Published) and the date
and time of publication.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;publish_post.png&quot; alt=&quot;Publishing a post&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After adding our post, the page now looks like this&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;published_post.png&quot; alt=&quot;A published post&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I will better explain what the options above mean next.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;&#x2F;h2&gt;
&lt;p&gt;That already looks much like a blog, but what if we wanted to use our own base
template (the one containing the header&#x2F;navbar), or show the categories on the
sidebar. If you want to change the settings for w3blog, you need to add the
&lt;code&gt;WEBLOG_SETTINGS&lt;&#x2F;code&gt; dictionary to your settings.py. The following are available
settings that you can change (with their defaults):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;WEBLOG_SETTINGS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;enable_comments&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;allow_anon_comments&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;multilingual&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;blog_title&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Django-Weblog&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;base_template&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;weblog_base.html&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;show_author&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;use_authors_username&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;show_sidebar&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;show_categories&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;show_archive&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;posts_per_page&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;enable_rss&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;home_title&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Welcome to the blog!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So most of them are pretty self explanatory, but I will explain them to avoid
confusion nonetheless:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;enable_comments -- set to True to enable users to post comments on the posts.&lt;&#x2F;li&gt;
&lt;li&gt;allow_anon_comments -- allow anonymous comments.&lt;&#x2F;li&gt;
&lt;li&gt;multilingual -- enable multilingual features, i.e. translations of posts.&lt;&#x2F;li&gt;
&lt;li&gt;blog_title -- the title of the blog, will be used on the blog&#x27;s homepage and
title tag&lt;&#x2F;li&gt;
&lt;li&gt;base_template -- which base template to use. If not set, will use w3blog&#x27;s
default template.&lt;&#x2F;li&gt;
&lt;li&gt;show_author -- set to True to display the author of the post on each post&lt;&#x2F;li&gt;
&lt;li&gt;use_authors_username -- set to True to use the author&#x27;s username (e.g.
author66) instead of their full name (e.g. John Smith).&lt;&#x2F;li&gt;
&lt;li&gt;show_sidebar -- set to True to show the sidebar (where the category and
archive lists reside).&lt;&#x2F;li&gt;
&lt;li&gt;show_categories -- set to True to show the categories list on the sidebar
(won&#x27;t show if you disabled the sidebar)&lt;&#x2F;li&gt;
&lt;li&gt;show_archive -- set to True to show the archive list on the sidebar (won&#x27;t
show if you disabled the sidebar)&lt;&#x2F;li&gt;
&lt;li&gt;posts_per_page -- the number of pages to display per page.&lt;&#x2F;li&gt;
&lt;li&gt;enable_rss -- set to True to enable the RSS feed (&#x2F;rss)&lt;&#x2F;li&gt;
&lt;li&gt;home_title -- if set, it will display on the blog&#x27;s home page instead of
blog_title (but blog_title will display in the title tag).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Now, you most probably will want to use your own template, in that case, make
sure to add the following to your template&#x27;s head tag&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;jinja2&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-jinja2 &quot;&gt;&lt;code class=&quot;language-jinja2&quot; data-lang=&quot;jinja2&quot;&gt;&lt;span&gt;&amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;meta content=&amp;quot;width=device-width, initial-scale=1&amp;quot; name=&amp;quot;viewport&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;title&amp;gt;{{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;blog_title &lt;&#x2F;span&gt;&lt;span&gt;}} - {% &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;block &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;title_block &lt;&#x2F;span&gt;&lt;span&gt;%} Home {% &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;endblock &lt;&#x2F;span&gt;&lt;span&gt;%}&amp;lt;&#x2F;title&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https:&#x2F;&#x2F;stackpath.bootstrapcdn.com&#x2F;bootstrap&#x2F;4.1.0&#x2F;css&#x2F;bootstrap.min.css&amp;quot; integrity=&amp;quot;sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4&amp;quot; crossorigin=&amp;quot;anonymous&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https:&#x2F;&#x2F;use.fontawesome.com&#x2F;releases&#x2F;v5.0.13&#x2F;css&#x2F;all.css&amp;quot; integrity=&amp;quot;sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp&amp;quot; crossorigin=&amp;quot;anonymous&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;{% &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;weblog&#x2F;css&#x2F;weblog.css&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;%}&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;script src=&amp;quot;https:&#x2F;&#x2F;code.jquery.com&#x2F;jquery-3.3.1.slim.min.js&amp;quot; integrity=&amp;quot;sha384-q8i&#x2F;X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo&amp;quot; crossorigin=&amp;quot;anonymous&amp;quot;&amp;gt;&amp;lt;&#x2F;script&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;script src=&amp;quot;https:&#x2F;&#x2F;cdnjs.cloudflare.com&#x2F;ajax&#x2F;libs&#x2F;popper.js&#x2F;1.14.0&#x2F;umd&#x2F;popper.min.js&amp;quot; integrity=&amp;quot;sha384-cs&#x2F;chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY&#x2F;&#x2F;20VyM2taTB4QvJ&amp;quot; crossorigin=&amp;quot;anonymous&amp;quot;&amp;gt;&amp;lt;&#x2F;script&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;script src=&amp;quot;https:&#x2F;&#x2F;stackpath.bootstrapcdn.com&#x2F;bootstrap&#x2F;4.1.0&#x2F;js&#x2F;bootstrap.min.js&amp;quot; integrity=&amp;quot;sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt&#x2F;6v9KI65qnm&amp;quot; crossorigin=&amp;quot;anonymous&amp;quot;&amp;gt;&amp;lt;&#x2F;script&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;script src=&amp;quot;{% &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;static &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;weblog&#x2F;js&#x2F;weblog.js&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;%}&amp;quot; defer&amp;gt;&amp;lt;&#x2F;script&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another option, if you don&#x27;t want to use bootstrap, would be to use your own
css files using bootstrap&#x27;s classes. You will want to check the templates&#x27;
source code of my engine for reference in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Yaroslav-95&#x2F;w3blog&#x2F;blob&#x2F;master&#x2F;weblog&#x2F;templates&#x2F;weblog_base.html&quot;&gt;w3blog&#x27;s GitHub
page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-w3blog&quot;&gt;Using w3blog&lt;&#x2F;h2&gt;
&lt;p&gt;Let us go back a little bit and discuss how to use w3blog. As we saw in the
beginning, you can add posts and categories through the admin. Let&#x27;s focus on
the adding posts part by checking this screenshot&lt;&#x2F;p&gt;
&lt;p&gt;As you can see, there are several option there to chose from&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Preview image -- use this to upload an image that you want to be displayed in
the preview of your post (in the home&#x2F;category&#x2F;archive page)&lt;&#x2F;li&gt;
&lt;li&gt;Preview text -- use this to set the text that will be displayed in the
preview of your post. If you don&#x27;t set it, w3blog will automatically use the
first paragraph of your post&#x27;s body as preview text.&lt;&#x2F;li&gt;
&lt;li&gt;Original language (ISO) -- the ISO code of the original language of your post
(e.g. &quot;en&quot;). This setting is not mandatory, and if you don&#x27;t set and have
translations for your post, it will assume that the original language is the
one set in your settings.py file (LANGUAGE variable).&lt;&#x2F;li&gt;
&lt;li&gt;Slug (URL) -- this will be the url part of your post. If you still don&#x27;t
understand what a slug is, Check out this link.&lt;&#x2F;li&gt;
&lt;li&gt;Categories -- the category or categories that your post will belong to. If
none are set, your post will be categorized under an &quot;Uncategorized&quot;
category. Important note here: you should not set the slug of a category to
&quot;misc&quot; since that is already used by weblog to display posts without a
category.&lt;&#x2F;li&gt;
&lt;li&gt;Pin blog post -- use this if you want to pin the post to the home page and
show above the rest of the posts&lt;&#x2F;li&gt;
&lt;li&gt;Pinned post priority -- if you pinned several posts, you use this to set
their priority&lt;&#x2F;li&gt;
&lt;li&gt;Published -- this sets whether the post is available to your readers. This
can be useful, for example, when you&#x27;ve started writing a post, but haven&#x27;t
finished and want to save a draft of it, so you don&#x27;t check this checkbox so
that it doesn&#x27;t display in your blog.&lt;&#x2F;li&gt;
&lt;li&gt;Publish date -- date and time the post was published.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Let&#x27;s try making a new post and setting it to pinned, to see what happens&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;pinned_post.png&quot; alt=&quot;Adding a pinned post&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So it will appear in our homepage at the very beginning&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;pinned_post2.png&quot; alt=&quot;A pinned post&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;translations&quot;&gt;Translations&lt;&#x2F;h2&gt;
&lt;p&gt;Adding a translation to a post is really simple if we have the multilingual
feature enabled in the settings. While adding our post, or after adding it, we
can go to the bottom of the add blog post page and add it. We will see some
similar options to the ones for the original blog post.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s suppose I want to add a Spanish translation. For that, I would type in
&quot;es&quot; as Language, and then just type the title, content, and if needed, the
preview image and text for my Spanish translation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;post_en_espa%C3%B1ol.png&quot; alt=&quot;Creando un post en español&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After saving, if we go to the blog with computer or browser with Spanish
language locale set, we will the site in spanish with the aforementioned&#x27;s post
Spanish translation&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;post_en_espa%C3%B1ol2.png&quot; alt=&quot;Este es un post en español&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Or if we go to the post itself, we will see an option to choose to read the option in a different language.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;w3blog-blog-engine&#x2F;multilang_post.png&quot; alt=&quot;Multi-language post&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Similarly, we can add translations for each category, if we so wish.&lt;&#x2F;p&gt;
&lt;p&gt;So, this is basically it on how to use w3blog to set up your own blog using
Django. I hope this post and my blog engine were useful to you. If you have any
questions you can &lt;del&gt;leave a comment here, or&lt;&#x2F;del&gt; contact me at my email
&lt;a href=&quot;mailto:contact@yaroslavps.com&quot;&gt;contact@yaroslavps.com&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you have found a bug or problem with w3blog, be sure to open an issue on
GitHub. The app is currently only translated to English, Spanish, and Russian,
so if you are willing to provide a translation for your language or any other
language that you know, you can send a pull request with the translated
strings, or download the strings for the git repository, translate them, and
send them to me so that I can compile them and add them to the project myself.&lt;&#x2F;p&gt;
&lt;p&gt;Thank you very much for reading this post, and I will be very happy to see your
projects using my blog engine!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Building and deploying a personal site with blog. Part 2</title>
		<published>2018-07-21T22:26:00+00:00</published>
		<updated>2018-07-21T22:26:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/building-deploying-personal-site-with-blog-pt2/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/building-deploying-personal-site-with-blog-pt2/</id>
		<content type="html">&lt;p&gt;Welcome back, this post is a continuation of the previous post in which I wrote
about how to initialize and setup a Django project for a personal site with
blog locally. Now we will be focusing on the juicy part, getting your site
deployed so that everyone on the interwebz can get to see &lt;del&gt;your nice new dank
memes in your very own site!&lt;&#x2F;del&gt; the fruits of your sweat and blood.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;&lt;em&gt;You might want to read &lt;a href=&quot;&#x2F;weblog&#x2F;building-deploying-personal-site-with-blog-pt1&#x2F;&quot;&gt;part one&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;part-ii-deploying-your-site&quot;&gt;Part II: Deploying your site&lt;&#x2F;h2&gt;
&lt;p&gt;I will assume that you already have bought a VPS or dedicated server in any of
the many hosting services available online, or maybe if you are cool enough,
might even have a machine of your own with a properly setup static IP address.
Note that if you are using shared hosting, the deployment process is usually
already automatized if they have support for Python and Django, if they don&#x27;t
support Python and Django, you need to get another hosting solution.&lt;&#x2F;p&gt;
&lt;p&gt;If you still don&#x27;t have any kind of hosting, and you are looking for a nice and
comfy VPS for your projects, I would recommend using DigitalOcean, you can get
a VPS powerful enough for Django and other Python web projects for as low as
$5. You can follow this referral link if you have decided to try DigitalOcean,
it will give a $10 credit for your first account, enough for two whole months
on their most inexpensive VPS.&lt;&#x2F;p&gt;
&lt;p&gt;Once you have your server set and ready to go, we can continue with the fun
part. Deploying your site. I will be assuming that you have a Debian-based
distro in your server.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;first-steps&quot;&gt;First steps&lt;&#x2F;h3&gt;
&lt;p&gt;First let&#x27;s make sure that our server is up to date&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo apt-get update
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo apt-get upgrade
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we need to install all the needed packages&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo apt-get install python3 python3-pip python-virtualenv postgresql nginx supervisor
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can set the virtual environment with your login user, or create another
user exclusively to run your Django project and other related stuff.&lt;&#x2F;p&gt;
&lt;p&gt;You can add a user to run the app like so&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; adduser webuser
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s go ahead and create a directory for virtual environments and create the environment for our project&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; virtualenv mysite&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; python3
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we source the environment&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; source mysite&#x2F;bin&#x2F;activate
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And use pip to install the necessary modules&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; pip install Django Pillow psycopg2 django-summernote w3blog
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that, we start and enable postgresql&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo systemctl start postgresql
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo systemctl enable postgresql
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Login to the postgres shell, set the password for user postgres, and create the
database for our project&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo su - postgres
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; psql
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;postgres&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;# &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;assword
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;postgres&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;# &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt; database mysitedb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, I am using the postgres user directly since I am using this
server just for myself, and I only use PSQL for my blog. However, if you host
multiple projects, and&#x2F;or multiple users have a more direct access to postgres,
you might want to create separate users and roles for each database or group of
databases.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;copying-your-django-project-to-the-server&quot;&gt;Copying your Django project to the server&lt;&#x2F;h3&gt;
&lt;p&gt;One way to copy your project files to the server would be using scp, for
example&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;scp&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -r&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;path&#x2F;to&#x2F;project user@serveripordomain:&#x2F;home&#x2F;webuser&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or if you are already hosting your project as a git repository in a service
like GitHub or BitBucket, you could clone directly into you repository in the
home folder, like so&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; git clone https:&#x2F;github.com&#x2F;user&#x2F;repo
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After the files have been copied, we need to set some things up for our Django
project. Before running this commads, you might need to export the needed
environmental variables, if you set up your Django settings using environmental
variables as I wrote in the first part. Otherwise, you might want to edit your
settings.py file now with the correct settings.&lt;&#x2F;p&gt;
&lt;p&gt;First we collect static files&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;manage.py collectstatic
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, we migrate our models to the database&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;manage.py migrate
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And after migrating we create a superuser for the Django admin&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;manage.py createsuperuser
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you get an authentication error while performing any of the above commands,
you will have to edit the following file&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudoedit &#x2F;etc&#x2F;postgresql&#x2F;9.1&#x2F;main&#x2F;pg_hba.conf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Change this line&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;local        all        postgres        peer
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So that it looks like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;local        all        postgres        md5
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;configuring-the-server&quot;&gt;Configuring the server&lt;&#x2F;h3&gt;
&lt;p&gt;I will be assuming that you are going to use nginx as a proxy server for
Django. There are other alternatives such as Apache, but I found nginx to be a
really powerful and easy to setup server.&lt;&#x2F;p&gt;
&lt;p&gt;First, while in our virtual environment, we will install gunicorn. We might
have been using Django&#x27;s own development server while building and testing our
app locally, but that&#x27;s what it is, a development server. It is not mean for
production, so we will use gunicorn for that&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pip&lt;&#x2F;span&gt;&lt;span&gt; install gunicorn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we&#x27;ll cd into our env&#x27;s bin folder and create a file called
&lt;code&gt;gunicorn_start&lt;&#x2F;code&gt;, and add the following lines to it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;#!&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;mysite&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Our site&amp;#39;s directory
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DIR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;home&#x2F;webuser&#x2F;mysite
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;USER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;webuser
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;GROUP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;webuser
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;WORKERS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;BIND&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;127.0.0.1:8001
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DJANGO_SETTINGS_MODULE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;mysite.settings
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DJANGO_WSGI_MODULE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;mysite.wsgi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;LOG_LEVEL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;error
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;cd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DIR
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;source&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;home&#x2F;webuser&#x2F;venvs&#x2F;mysite&#x2F;bin&#x2F;activate
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DJANGO_SETTINGS_MODULE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DJANGO_SETTINGS_MODULE
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PYTHONPATH&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DIR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PYTHONPATH
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# This are the environment variables needed for your Django settings
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# (see the first part of this guide)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_SECRETKEY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;YOURSECRETKEYGOESHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_DEBUG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_DBPASSWORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;YOURPOSTGRESPWDGOESHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_DBUSER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_HOST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;localhost&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;5342&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;exec&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;home&#x2F;webuser&#x2F;venvs&#x2F;mysite&#x2F;bin&#x2F;gunicorn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DJANGO_WSGI_MODULE&lt;&#x2F;span&gt;&lt;span&gt;}:application \
&lt;&#x2F;span&gt;&lt;span&gt;  --name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;NAME &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  --workers &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;WORKERS &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  --user=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;USER &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  --group=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;GROUP &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  --bind=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;BIND &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  --log-level=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;LOG_LEVEL &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  --log-file=-
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And make it executable&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; chmod a+x gunicorn_start
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s almost it, but before actually running gunicorn, we will install one
more program which will take care of the gunicorn server, so that if for any
reason we need to reboot our server, it will restart gunicorn for us. It needs
to be some kind of supervisor. Well why my dear friend, we are going to use
Supervisor.&lt;&#x2F;p&gt;
&lt;p&gt;But first, let&#x27;s create a folder name logs inside our webuser&#x27;s home folder,
and create a file to be used to log any application errors:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; mkdir logs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; touch logs&#x2F;gunicorn.log
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we create a new Supervisor config file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudoedit &#x2F;etc&#x2F;supervisor&#x2F;conf.d&#x2F;mysite.conf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cfg&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-cfg &quot;&gt;&lt;code class=&quot;language-cfg&quot; data-lang=&quot;cfg&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;[program:mysite]
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;command&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;home&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;webuser&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;venvs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;mysite&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;bin&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;gunicorn_start
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;webuser
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;autostart&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;autorestart&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;redirect_stderr&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;stdout_logfile&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;home&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;webuser&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;logs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;gunicorn&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;log
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We reread the Supervisor configuration files, and start the program:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo supervisorctl reread
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo supervisorctl update
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And check the status to make sure it is running fine and dandy&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo supervisorctl status mysite
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we should configure nginx, and for that we are going to make the
configuration file for our site. Open it up&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudoedit &#x2F;etc&#x2F;nginx&#x2F;sites-available&#x2F;mysite
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And add the following lines&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;        listen 80;
&lt;&#x2F;span&gt;&lt;span&gt;        listen [::]:80;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        server_name www.example.com;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F;static&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                alias &#x2F;home&#x2F;webuser&#x2F;mysite&#x2F;static&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F;media&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                alias &#x2F;home&#x2F;webuser&#x2F;mysite&#x2F;media&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_set_header Host $http_host;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_redirect off;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_pass http:&#x2F;&#x2F;127.0.0.1:8001;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I won&#x27;t be explaining in this guide how to setup an SSL certificate, since it
is out of its scope, but, if you want to get a free certificate, I cant point
you to letsencrypt.com. It is backed by many of the top internet organizations.
If you already have an SSL certificate, and would like to use HTTPS, your file
should look like this&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;        listen 80;
&lt;&#x2F;span&gt;&lt;span&gt;        listen [::]:80;
&lt;&#x2F;span&gt;&lt;span&gt;        server_name www.example.com;
&lt;&#x2F;span&gt;&lt;span&gt;        return 301 https:&#x2F;&#x2F;$host$request_uri;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;        listen 443 ssl;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        server_name www.example.com;
&lt;&#x2F;span&gt;&lt;span&gt;        ssl_certificate &#x2F;path&#x2F;to&#x2F;cert&#x2F;fullchain.pem;
&lt;&#x2F;span&gt;&lt;span&gt;        ssl_certificate_key &#x2F;path&#x2F;to&#x2F;key&#x2F;privkey.pem;
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F;static&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                alias &#x2F;home&#x2F;webuser&#x2F;mysite&#x2F;static&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F;media&#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                alias &#x2F;home&#x2F;webuser&#x2F;mysite&#x2F;media&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;        location &#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_set_header Host $http_host;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_redirect off;
&lt;&#x2F;span&gt;&lt;span&gt;                proxy_pass http:&#x2F;&#x2F;127.0.0.1:8001;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After creating the needed config file, we create a symbolic link to it in sites-enabled&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo ln&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -s&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;nginx&#x2F;sites-available&#x2F;mysite &#x2F;etc&#x2F;nginx&#x2F;sites-enabled&#x2F;mysite
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Remove the default nginx site&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo rm &#x2F;etc&#x2F;nginx&#x2F;sites-enabled&#x2F;default
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, we restart nginx&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo service nginx restart
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Et voila!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.yaroslavps.com&#x2F;weblog&#x2F;building-deploying-personal-site-with-blog-pt2&#x2F;result.png&quot; alt=&quot;It&amp;#39;s alive!&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;This was by no means the most comprehensive guide to Django, but it might help
you get started on setting up your own projects, and most importantly, actually
deploying them to a live server.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Building and deploying a personal site with blog. Part 1</title>
		<published>2018-07-21T21:46:00+00:00</published>
		<updated>2018-07-21T21:46:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/building-deploying-personal-site-with-blog-pt1/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/building-deploying-personal-site-with-blog-pt1/</id>
		<content type="html">&lt;p&gt;I will be explaining in this guide how I built, and how I deployed this site.
This will be a really simple tutorial, on how to do it using Python and Django.
You might want to have a little knowledge of Django and Python previous to
attempting to follow the instructions laid out in this tutorial, as the goal of
this tutorial is not to teach you the basic principles of either the Python
programming language, or Django framework. It is just meant as a little guide
on the basic workflow when building and deploying sites with Django.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;Initially I intended for the whole guide to be just one post, but I had to
break it into two posts since it ended up being too long. This first part will
focus on the initial process of setting up and building a kind of personal blog
site based on what I did for my own site, using the Django framework.&lt;&#x2F;p&gt;
&lt;p&gt;I will not be writing here on how I made the blog engine for this site, rather
I will be using a blog engine that I have made, called w3blog (you can read it
either as &quot;weblog&quot;, or as &quot;w3&#x2F;www blog&quot;). &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Yaroslav-95&#x2F;w3blog&quot;&gt;Checkout the GitHub page
here&lt;&#x2F;a&gt;. I will not be writing on this
guide all of the possible configurations of w3blog, I will be writing a
separate post about it soon (actually, I should also write thorough
documentation for the module, and I will, but while I get enough time to do it,
I will write a short post about it in the meantime).&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s get our hands dirty...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;part-i-building-and-getting-the-site-ready-for-deployment&quot;&gt;Part I: Building and getting the site ready for deployment&lt;&#x2F;h2&gt;
&lt;p&gt;Before getting started, we need to make that everything we need is installed.
In this case I am building my site using Python 3.6, and Django 2.0. I am also
using PostgreSQL as my database.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;first-steps&quot;&gt;First steps&lt;&#x2F;h3&gt;
&lt;p&gt;I am using Manjaro as my OS, so I already have installed Python 3.6. You should
also have Python 3.6 installed if you are using Ubuntu 18.04. PostgreSQL
doesn&#x27;t come by default, so using the terminal I installed postgres using the
following command (this is for Manjaro and other Arch based distros):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo pacman&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -S&lt;&#x2F;span&gt;&lt;span&gt; postgresql
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or for Ubuntu and other Debian-based distros:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo apt-get update
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo apt-get install postgresql
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you&#x27;re using Windows, these commands will obviously not be of much help
(unless you are using the Linux Subsystem for Windows, or whatever Micro$oft is
calling it these days).&lt;&#x2F;p&gt;
&lt;p&gt;I would recommend using Linux for web development (or any kind of development
(or any kind of use case for that matter)), especially with Python, or even Mac
OSX (or whatever Apple has taken to calling their OS these days), since it is
also Unix-like, and you have bash installed natively. However, if you do plan
on using Windows to develop your site, you should be able to download the
respective installers from their respective websites.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, back to the topic.&lt;&#x2F;p&gt;
&lt;p&gt;Next, we start PostgreSQL using systemd (or your init system of choice):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo systemctl start postgresql
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once we have Python and Postgres installed, we need to create a virtual
environment to keep all the packages that we need for our site all in one
place. Now, you could of course skip this step and just install the packages
system-wide, however, it is a better practice to have different environments
for different projects.&lt;&#x2F;p&gt;
&lt;p&gt;I am not going to be explaining the reasons for that since there already are a
lot of articles on the internetz which do a better job at explaining why, than
I would.&lt;&#x2F;p&gt;
&lt;p&gt;If you don&#x27;t have virtualenv installed, go ahead and do it now:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo pacman&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -S&lt;&#x2F;span&gt;&lt;span&gt; python-virtualenv
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo apt-get install python-virtualenv
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we cd into the directory where we want to keep our environments and do:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; virtualenv envname&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; python3
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After some seconds we should have a new folder with our new virtual
environment. To activate the environment we need to source the &quot;activate&quot;
script inside the environment, like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; source envname&#x2F;bin&#x2F;activate
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You should now notice the name of the environment on the left side of your
prompt. After that we can proceed to install with pip the packages that we
need, for example, to install Django:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; pip install Django
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The list of packages needed to build the site in this tutorial:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;Django
&lt;&#x2F;span&gt;&lt;span&gt;Pillow
&lt;&#x2F;span&gt;&lt;span&gt;psycopg2
&lt;&#x2F;span&gt;&lt;span&gt;django-summernote
&lt;&#x2F;span&gt;&lt;span&gt;w3blog
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pillow is a package used by Django to work with images saved on the database.
psycopg2 is needed to use PostgreSQL with and Django. w3blog is my blog engine,
it makes use of django-summernote, a module to integrate the wonderful editor
summernote. You can find out more about it &lt;a href=&quot;https:&#x2F;&#x2F;summernote.org&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;starting-and-setting-up-the-project&quot;&gt;Starting and setting up the project&lt;&#x2F;h3&gt;
&lt;p&gt;After that we are ready to initialize our project. We cd into a directory where
we usually keep all our projects, and tell django to initialize it for us&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; django-admin startproject mysite
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Django will create the basic directory structure for our project and generate
some basic files to get started. If you run &quot;manage.py runserver&quot; right now you
will get the welcome screen from Django telling you your project has been
correctly initialized. I will be skipping that part and go on ahead and start
configuring my project as needed.&lt;&#x2F;p&gt;
&lt;p&gt;First let&#x27;s set up the &lt;code&gt;settings.py&lt;&#x2F;code&gt; file by modifying the following settings,
the other we can leave for the time being:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.utils.translation &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;ugettext_lazy &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;_
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SECRET_KEY &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;os.environ.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;SITE_SECRETKEY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DEBUG &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;os.environ.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;SITE_DEBUG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DATABASES &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;ENGINE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;django.db.backends.postgresql&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;sitedb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;USER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: os.environ.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;SITE_DBUSER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;PASSWORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: os.environ.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;SITE_DBPASSWORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;HOST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: os.environ.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;SITE_DBHOST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: os.environ.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;SITE_DBPORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;LANGUAGE_CODE &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;en-us&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;LANGUAGES &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;es&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Spanish&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;        (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;en&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;English&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;        (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;ru&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Russian&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;LOCALEPATHS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;os.path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;BASE_DIR&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;locale&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;TIME_ZONE &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Europe&#x2F;Moscow&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;USE_I18N &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;USE_L10N &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;USE_TZ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;STATIC_URL &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;static&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;MEDIA_URL &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;media&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;MEDIA_ROOT &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;os.path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;BASE_DIR&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;media&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You may have noticed that I am using &lt;code&gt;os.environ.get(&#x27;ENVVAR_NAME&#x27;)&lt;&#x2F;code&gt; to get
some of my settings from environmental variables, instead of typing those
settings directly into my file. Part of the reason I do that, is because it is
not safe to store information such as passwords, or secret keys in your code.&lt;&#x2F;p&gt;
&lt;p&gt;Also, since not all of my settings are the same in my local, or testing
machine, as in my server or production machine, this makes it more convenient
and easier, since I don&#x27;t have to keep two different &quot;settings.py&quot; files, and I
don&#x27;t risk the chance of, for example, uploading my passwords, and other
private information to a service like GitHub, or BitBucket, should I decide to
publicly host the source code of my site.&lt;&#x2F;p&gt;
&lt;p&gt;There are other reasons for that, and there are other ways to keep config
separated from code, but I will not be going into much detail now.&lt;&#x2F;p&gt;
&lt;p&gt;To export the environmental variables while you&#x27;re developing, you can create a
script (for example variables.sh) that will export them for you, it should
something like this&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;#!&#x2F;bin&#x2F;sh
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_SECRETKEY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;YOURSECRETKEYGOESHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_DEBUG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_DBPASSWORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;YOURPOSTGRESPWDGOESHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_DBUSER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_HOST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;localhost&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;SITE_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;5342&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To export the variables from the file to your current shell you would run
either&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; source variables.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;or&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; . variables.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both work equally fine.&lt;&#x2F;p&gt;
&lt;p&gt;The other settings are the language and locale settings. This is an example of
my settings, so you should them accordingly to your needs. For example, my site
is available in three languages, so I them accordingly in the &lt;code&gt;LANGUAGES&lt;&#x2F;code&gt;
tuple, and also enabled Django&#x27;s localization services by setting the
&lt;code&gt;USE_I18N&lt;&#x2F;code&gt; and &lt;code&gt;USE_L10N&lt;&#x2F;code&gt; variables to True.&lt;&#x2F;p&gt;
&lt;p&gt;If you want Django to translate your site according to the user settings
automatically, you also need to add the following to &lt;code&gt;MIDDLEWARE&lt;&#x2F;code&gt; before
&lt;code&gt;CommonMiddleWare&lt;&#x2F;code&gt;, but after &lt;code&gt;SessionMiddleware&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;django.middleware.locale.LocaleMiddleware&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The last three settings back there, are so that Django knows where to look for
static files such as images, css, js, etc. And so that it knows where to save
and look for images belonging to models in the database, for example, if a user
uploads a picture, or this case, if I embed an image in one of my blog posts.&lt;&#x2F;p&gt;
&lt;p&gt;Let us not forget about adding the modules that we downloaded with pip to the list of installed apps:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;INSTALLED_APPS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;django-summernote&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;weblog&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And set our allowed hosts:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ALLOWED_HOSTS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;127.0.0.1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;mysite.xyz&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;configuring-the-db&quot;&gt;Configuring the DB&lt;&#x2F;h3&gt;
&lt;p&gt;With these settings, we can now migrate our models to the database. However,
before doing that we need to set up the database in PostgreSQL. For that we
need to open up the terminal and switch to user postgres, and open up the psql
shell:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; sudo su - postgres
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; psql
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Inside the shell, if you haven&#x27;t set up a password for user postgres, do so
now:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;postgres&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;# &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;assword
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that, we create our database&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;postgres&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;# &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt; database sitedb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And NOW, we can migrate our models. Let us do so by going back to our project&#x27;s
root directory, and typing:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;manage.py migrate
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If for some reason, it complains to you about some model migrations conflicts,
go ahead and do the following, typing &quot;y&quot; when it prompts you:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;manage.py makemigrations&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; --merge
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After migrating we can create a superuser so that we can enter the Django admin
site:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# .&#x2F;manage.py createsuperuser
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;launching-the-project&quot;&gt;Launching the project&lt;&#x2F;h3&gt;
&lt;p&gt;One final thing before our site is ready for use. We need to add the
corresponding urls for the w3blog engine, and summernote editor in our projects
main &lt;code&gt;urls.py&lt;&#x2F;code&gt; file. So let&#x27;s go ahead and add them, our urls.py file should like
this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.contrib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;admin
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.conf &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;settings
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.urls &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;path, include
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.conf.urls.static &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;static
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;urlpatterns &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;admin&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, admin.site.urls),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;summernote&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;include&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;django_summernote.urls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;include&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;weblog.urls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;settings.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;DEBUG&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    urlpatterns &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;static&lt;&#x2F;span&gt;&lt;span&gt;(settings.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;MEDIA_URL&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;document_root&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;settings.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;MEDIA_ROOT&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we if we launch our development server&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;manage.py runserver
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And go to &lt;code&gt;127.0.0.1:8000&lt;&#x2F;code&gt; in our browser, we should see a basic blog site with
no posts on it yet, however, if we go to the django admin page, we can some
posts, and so our site is not so empty anymore!&lt;&#x2F;p&gt;
&lt;p&gt;Now, if you are planning on having some other things on you site besides the
blog, you need to start a new django app inside your project&#x27;s root directory&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; django-admin startapp myapp
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add an include to it&#x27;s urls config to the main urls.py file. So your project&#x27;s
urlpatterns variable now might be looking something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span&gt;urlpatterns &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;admin&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, admin.site.urls),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;summernote&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;include&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;django_summernote.urls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;weblog&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;include&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;weblog.urls&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;include&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;myapp&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And don&#x27;t forget to add your app&#x27;s name to the &lt;code&gt;INSTALLED_APPS&lt;&#x2F;code&gt; list in
&quot;settings.py&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;This is it for part 1 of this little guide. Soon I will post the second part where I&#x27;ll write about how I deployed my site to a Debian server.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;weblog&#x2F;building-deploying-personal-site-with-blog-pt2&#x2F;&quot;&gt;Continue reading part two here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>A weblog by Yaroslav de la Peña Smirnov</title>
		<published>2018-07-21T20:06:00+00:00</published>
		<updated>2018-07-21T20:06:00+00:00</updated>
		<link href="https://www.yaroslavps.com/weblog/first-post/" type="text/html"/>
		<id>https://www.yaroslavps.com/weblog/first-post/</id>
		<content type="html">&lt;p&gt;Hello, and welcome to my weblog. As you may have read in my home page, I will be
writing here mainly about what I do, and how I do it. That is, I aim to make a
sort of compendium for myself as a self-learning tool; for future reference,
when I need to refresh my memory, and of course for anybody else that shares my
interests and wishes to learn something new. I am by no means an expert, but I
believe that it is easier to learn by sharing your knowledge.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;I will be writing mainly in English, but I also plan on making most (probably
all of them) of my posts available in Spanish and Russian.&lt;&#x2F;p&gt;
&lt;p&gt;Grab a cup of tea (or any kind of refreshment you might prefer), sit down, and
feel free to browse through my weblog.&lt;&#x2F;p&gt;
&lt;p&gt;On my next post I will write about the steps that I took to build this site and
deploy it. So if you are interested in building sites using Django and Python as
I am, you might want to check out the next post when it comes out. You can also
add this blog&#x27;s RSS feed to your favorite reader so you don&#x27;t miss anything.&lt;&#x2F;p&gt;
&lt;p&gt;Note: While my blog isn&#x27;t so visited I plan on allowing anonymous (i.e. without
having to register) comments. If I start to get a lot of spammers, I will have
to turn them off until I integrate a better system for comments. So feel free to
leave your comments! All comments and suggestions are welcome (as long as they
are kept in a civilized manner).&lt;&#x2F;p&gt;
</content>
	</entry>
</feed>
