<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ihor Kalnytskyi</title>
    <description>The latest articles on DEV Community by Ihor Kalnytskyi (@ikalnytskyi).</description>
    <link>https://dev.to/ikalnytskyi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F924587%2Fb7a1e15f-e86d-44e6-9e6f-f383236e4c26.jpeg</url>
      <title>DEV Community: Ihor Kalnytskyi</title>
      <link>https://dev.to/ikalnytskyi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ikalnytskyi"/>
    <language>en</language>
    <item>
      <title>Setup a WireGuard client using systemd-networkd</title>
      <dc:creator>Ihor Kalnytskyi</dc:creator>
      <pubDate>Sat, 03 Sep 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/ikalnytskyi/setup-a-wireguard-client-using-systemd-networkd-62b</link>
      <guid>https://dev.to/ikalnytskyi/setup-a-wireguard-client-using-systemd-networkd-62b</guid>
      <description>&lt;p&gt;&lt;em&gt;Please check out &lt;a href="https://dev.to/ikalnytskyi/setup-a-wireguard-server-using-systemd-networkd-42nb"&gt;«Setup a WireGuard server using systemd-networkd»&lt;/a&gt; to learn more about WireGuard in general and network topology outlined in this post.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;On Feb 24, 2022, Russia began a full scale invasion of Ukraine. The terror they brought to my country is devastating, and so publication of this post has been postponed till better times. Only now I finally found some strength inside to finish and publish this writing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;WireGuard is a great VPN choice for your home, and maybe even for your company. It's simple, fast, built into Linux kernel 5.6 and above, and can be configured via &lt;a href="https://man.archlinux.org/man/systemd-networkd.8.en"&gt;systemd-networkd&lt;/a&gt; in no time. The systemd suite supports WireGuard starting with v237 and is most likely installed on your Linux machine.&lt;/p&gt;

&lt;p&gt;Let us try to setup a wireguard 'client' for the following VPN network:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.0/24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.20&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;First thing to do is to set up a virtual network device for a WireGuard tunnel. This can be achieved by means of a &lt;a href="https://man.archlinux.org/man/systemd.netdev.5"&gt;systemd.netdev(5)&lt;/a&gt; unit that must be created in &lt;code&gt;/etc/systemd/network/&lt;/code&gt; directory. The WireGuard network device must know about number of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The private key of the peer.&lt;/li&gt;
&lt;li&gt;The endpoint of the 'server' peer and its public key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike 'server', a 'client' peer doesn't require port configuration because it's the 'client' that initiates connection not the other way round. This is how some &lt;code&gt;/etc/systemd/network/wg0.netdev&lt;/code&gt; could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[NetDev]
Name=wg0
Kind=wireguard
Description=wg0 - wireguard tunnel

[WireGuard]
PrivateKeyFile=/etc/systemd/network/wireguard-keys/wg0
FirewallMark=0x8888

[WireGuardPeer]
PublicKey=TPouHhVqvgAMfa9mNwZOh59kifUAsdn9Vtgsj2IsKVU=
AllowedIPs=0.0.0.0/0
Endpoint=vpn.example.com:51820
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The content of &lt;code&gt;/etc/systemd/network/wg0.key&lt;/code&gt; can be generated by invoking&lt;code&gt;$ wg genkey&lt;/code&gt; command and must be readable by the &lt;code&gt;systemd-network&lt;/code&gt; user.&lt;/p&gt;

&lt;p&gt;There are couple of things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;FirewallMark&lt;/code&gt; option takes a number and is used to mark outgoing WireGuard packets. Please remember that mark, it will be later used for network configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;AllowedIPs&lt;/code&gt; option is set to &lt;code&gt;0.0.0.0/0&lt;/code&gt; because we're interested to route all the traffic via the tunnel, i.e. surfing the Internet via VPN. If your plans for the VPN is to connect multiple devices into a single network, you should go with the network address only, e.g. &lt;code&gt;10.0.0.0/24&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;Endpoint&lt;/code&gt; option takes a wireguard 'server' IP address or hostname, followed by a colon, and then a port the 'server' accepts connection on. The endpoint must be reachable from 'client' peers even when VPN is down.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next thing to do is to use a &lt;a href="https://man.archlinux.org/man/systemd.network.5"&gt;systemd.network(5)&lt;/a&gt; unit to setup a network. The purpose of the network is to assign a proper IP address on the network device, set proper routes and so on.&lt;/p&gt;

&lt;p&gt;This how some &lt;code&gt;/etc/systemd/network/wg0.network&lt;/code&gt; could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Match]
Name=wg0

[Network]
Address=10.0.0.20/24
DNSDefaultRoute=true
DNS=1.1.1.1

[Link]
ActivationPolicy=manual

[RoutingPolicyRule]
FirewallMark=0x8888
InvertRule=true
Table=1000
Priority=10

[Route]
Gateway=10.0.0.1
GatewayOnLink=true
Table=1000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a bunch of important stuff going on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Since &lt;code&gt;/24&lt;/code&gt; network mask is used, systemd-networkd will automatically add a route for the whole network to be routed via the WireGuard tunnel. Without that mask, it'd be up to a user to properly configure routing on the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;With &lt;code&gt;ActivationPolicy&lt;/code&gt; set to &lt;code&gt;manual&lt;/code&gt;, the VPN is not brought up on system boot, and requires manual activation via &lt;code&gt;$ networkctl up wg0&lt;/code&gt;. One case use the &lt;code&gt;up&lt;/code&gt; value to always activate VPN on system boot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Both &lt;code&gt;RoutingPolicyRule&lt;/code&gt; and &lt;code&gt;Route&lt;/code&gt; come together and are only required if you want to route all the traffic over the tunnel. The &lt;code&gt;Route&lt;/code&gt; section essentially creates a default route that routes packets to the wireguard server. The &lt;code&gt;RoutingPolicyRule&lt;/code&gt; section, on the other hand, says that this new default route should be applied only for the packets not coming from the wireguard network device (i.e. not being marked with a firewall mark).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When VPN is used as a gateway for the Internet, it's quite common to set some non default DNS servers to resolve domain names. It could be your own VPN server, or some third-party provider such as Cloudflare. In order to set custom DNS servers when VPN connection is up, one can use &lt;code&gt;DNSDefaultRoute&lt;/code&gt; and &lt;code&gt;DNS&lt;/code&gt; options. The former tells the system to use the latter to resolve all domain names.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When both the network device and the network are configured, the only remained step is to run &lt;code&gt;$ networkctl reload&lt;/code&gt; to pipe in and apply latest configuration followed by &lt;code&gt;$networkctl up wg0&lt;/code&gt; to bring the VPN up.&lt;/p&gt;

</description>
      <category>wireguard</category>
      <category>vpn</category>
      <category>systemd</category>
      <category>linux</category>
    </item>
    <item>
      <title>Setup a WireGuard server using systemd-networkd</title>
      <dc:creator>Ihor Kalnytskyi</dc:creator>
      <pubDate>Mon, 07 Feb 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/ikalnytskyi/setup-a-wireguard-server-using-systemd-networkd-42nb</link>
      <guid>https://dev.to/ikalnytskyi/setup-a-wireguard-server-using-systemd-networkd-42nb</guid>
      <description>&lt;p&gt;&lt;em&gt;Please check out &lt;a href="https://dev.to/ikalnytskyi/setup-a-wireguard-client-using-systemd-networkd-62b"&gt;«Setup a WireGuard client using systemd-networkd»&lt;/a&gt; to learn about client-side configuration of your Linux machine.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;WireGuard is an extremely simple, fast and modern VPN that is built into Linux kernel 5.6 (released on Mar 29, 2020) and above. It mimics the model of SSH and requires VPN peers to know each others public keys. I highly recommend to read &lt;a href="https://www.wireguard.com"&gt;https://www.wireguard.com&lt;/a&gt; regardless of this post.&lt;/p&gt;

&lt;p&gt;When it comes to WireGuard, there's one interesting aspect: it has no notion of 'server', it's distributed by design and no blockchain is involved. Blockchain enthusiasts may found this surprising but distributed software were invented long before the blockchain 😅. Each peer may connect to other peers assuming they know each other (i.e. public key, IP) and there's a connectivity between them. The 'server' is rather a behaviour one may expect from a certain peer. There are 3 key points that are normally expected from a 'server' peer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The peer is publicly available, so other peers may connect to it even when behind SNAT.&lt;/li&gt;
&lt;li&gt;The peer can act as a proxy and connect other peers into a single network.&lt;/li&gt;
&lt;li&gt;The peer can act as a gateway to the Internet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are number of ways to configure WireGuard on a Linux machine. My favorite one is to use &lt;a href="https://man.archlinux.org/man/systemd-networkd.8.en"&gt;systemd-networkd&lt;/a&gt;, a system service that manages both networks and network devices. It's distributed as part of systemd suite, so most likely you have it installed, and it supports WireGuard starting with v237. It's a good choice for a Linux server because it requires no extra software.&lt;/p&gt;

&lt;p&gt;For instance we want to setup the following VPN network:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.0/24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peer A&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.20&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peer B&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.30&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;First thing to do is to set up a virtual network device for a WireGuard tunnel. This can be achieved by means of a &lt;a href="https://man.archlinux.org/man/systemd.netdev.5"&gt;systemd.netdev(5)&lt;/a&gt; unit that must be created in &lt;code&gt;/etc/systemd/network/&lt;/code&gt; directory. The WireGuard network device must know about number of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The port to accept new connections on.&lt;/li&gt;
&lt;li&gt;The private key of the server.&lt;/li&gt;
&lt;li&gt;The list of known peers and their public keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how some &lt;code&gt;/etc/systemd/network/wg0.netdev&lt;/code&gt; could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[NetDev]
Name=wg0
Kind=wireguard
Description=wg0 - wireguard tunnel

[WireGuard]
ListenPort=51820
PrivateKeyFile=/etc/systemd/network/wg0.key

[WireGuardPeer]
AllowedIPs=10.0.0.20/32
PublicKey=9vzzasvYciJLmhjrt9Aj9aQYe1gnUxI44ShVLQPrDQA=

[WireGuardPeer]
AllowedIPs=10.0.0.30/32
PublicKey=9vzzasvYciJLmhjrt9Aj9aQYe1gnUxI44ShVLQPrDQA=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The content of &lt;code&gt;/etc/systemd/network/wg0.key&lt;/code&gt; can be generated by invoking&lt;code&gt;$ wg genkey&lt;/code&gt; command and must be readable by the &lt;code&gt;systemd-network&lt;/code&gt; user. What's notable here is that &lt;code&gt;$ wg genkey&lt;/code&gt; can be executed anywhere, even on your laptop, there's no need to install extra software on the server.&lt;/p&gt;

&lt;p&gt;Next thing to do is to use a &lt;a href="https://man.archlinux.org/man/systemd.network.5"&gt;systemd.network(5)&lt;/a&gt; unit to setup a network. The purpose of the network is to assign a proper IP address on the network device, set proper routes and so on.&lt;/p&gt;

&lt;p&gt;This how some &lt;code&gt;/etc/systemd/network/wg0.network&lt;/code&gt; could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Match]
Name=wg0

[Network]
Address=10.0.0.1/24
IPMasquerade=both
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are couple of things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Since &lt;code&gt;/24&lt;/code&gt; network mask is used, systemd-networkd will automatically add a route for the whole network to be routed via the WireGuard tunnel. Without that mask, it'd be up to a user to properly configure routing on the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;IPMasquerade&lt;/code&gt; setting is only needed if the server is expected to be used as a gateway to the Internet. Without this option, it'd be up to a user to properly configure the firewall.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When both the network device and the network are configured, the only remained step is to run &lt;code&gt;$ networkctl reload&lt;/code&gt; to pipe in and apply latest configuration.&lt;/p&gt;

</description>
      <category>wireguard</category>
      <category>vpn</category>
      <category>systemd</category>
      <category>linux</category>
    </item>
    <item>
      <title>Setup CORS in Caddy 2</title>
      <dc:creator>Ihor Kalnytskyi</dc:creator>
      <pubDate>Wed, 12 Jan 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/ikalnytskyi/setup-cors-in-caddy-2-3i58</link>
      <guid>https://dev.to/ikalnytskyi/setup-cors-in-caddy-2-3i58</guid>
      <description>&lt;p&gt;&lt;a href="https://caddyserver.com/"&gt;Caddy 2&lt;/a&gt; is an open source web server with automatic HTTPS. It's a wise choice for pet projects or self-hosted services, since you are free from managing TLS certs on your own and wiring things up can be super annoying.&lt;/p&gt;

&lt;p&gt;One missing feature in Caddy 2, however, is cross-origin resource sharing (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"&gt;CORS&lt;/a&gt;) support. For a "batteries included" web server, it's rather surprising. Fortunately, one can use the following &lt;a href="https://caddyserver.com/docs/caddyfile/concepts#snippets"&gt;Caddy snippet&lt;/a&gt; to augment any site with CORS headers without repeating oneself over and over again.&lt;/p&gt;

&lt;p&gt;You might want to update the list of headers returned by&lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt; or &lt;code&gt;Access-Control-Expose-Headers&lt;/code&gt; HTTP headers according to your application needs. Please refer to the CORS documentation to learn more what they are about.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(cors) {
  @cors_preflight method OPTIONS
  @cors header Origin {args.0}

  handle @cors_preflight {
    header Access-Control-Allow-Origin "{args.0}"
    header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE"
    header Access-Control-Allow-Headers "Content-Type"
    header Access-Control-Max-Age "3600"
    respond "" 204
  }

  handle @cors {
    header Access-Control-Allow-Origin "{args.0}"
    header Access-Control-Expose-Headers "Link"
  }
}

example.com {
  import cors https://example.com
  reverse_proxy localhost:8080
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nice part about this snippet is that CORS headers are only returned for HTTP requests with the &lt;code&gt;Origin&lt;/code&gt; HTTP header. That header is normally used by browsers only, which means you won't see CORS headers in responses for requests sent by &lt;code&gt;curl&lt;/code&gt; or &lt;em&gt;your-programming-language-of-choice&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I've been successfully using this snippet for quite a while now &lt;a href="https://github.com/xsnippet/xsnippet-infra/blob/1d583a6868597cb71bb2ae08f60bc42ac4364e91/roles/xsnippet_api/templates/caddy.j2#L1-L17"&gt;to protect&lt;/a&gt; &lt;a href="https://api.xsnippet.org"&gt;api.xsnippet.org&lt;/a&gt;, so it can be accessed by &lt;a href="https://xsnippet.org"&gt;xsnippet.org&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>caddy</category>
      <category>caddyserver</category>
      <category>server</category>
      <category>cors</category>
    </item>
    <item>
      <title>Setup PostgreSQL for Linux, Windows and macOS using GitHub Actions</title>
      <dc:creator>Ihor Kalnytskyi</dc:creator>
      <pubDate>Wed, 24 Nov 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/ikalnytskyi/setup-postgresql-for-linux-windows-and-macos-using-github-actions-3fhd</link>
      <guid>https://dev.to/ikalnytskyi/setup-postgresql-for-linux-windows-and-macos-using-github-actions-3fhd</guid>
      <description>&lt;p&gt;GitHub Actions is a CI/CD platform that is widely used among open-source software hosted on GitHub. If you happened to host your software there, you may end up needing a SQL server to test your application. PostgreSQL is the most common choice nowadays.&lt;/p&gt;

&lt;p&gt;As of today (Nov 24, 2021), there's only one &lt;a href="https://github.com/marketplace/actions/setup-postgresql-for-linux-macos-windows"&gt;action on the marketplace&lt;/a&gt; to setup a PostgreSQL server for Linux, Windows and macOS action runners. If you among those who want to test their software on all major platforms, you have no option but to use &lt;a href="https://github.com/ikalnytskyi/action-setup-postgres"&gt;ikalnytskyi/action-setup-postgres&lt;/a&gt;. Below is the typical usage example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;steps:
  - name: Setup PostgreSQL
    uses: ikalnytskyi/action-setup-postgres@v1
    id: postgres

  - name: Run tests
    env:
      CONNECTION_URI: ${{ steps.postgres.outputs.connection-uri }}
    run: pytest -vv tests/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So why use that exact action and no other?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs on Linux, macOS and Windows action runners.&lt;/li&gt;
&lt;li&gt;Fast! Preinstalled binaries are used.&lt;/li&gt;
&lt;li&gt;Easy to audit, just &lt;a href="https://github.com/ikalnytskyi/action-setup-postgres/blob/v1/action.yml"&gt;4 steps YAML&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>postgres</category>
      <category>github</category>
      <category>actions</category>
      <category>ci</category>
    </item>
    <item>
      <title>Enable CSD in GNOME Terminal</title>
      <dc:creator>Ihor Kalnytskyi</dc:creator>
      <pubDate>Sun, 24 Oct 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/ikalnytskyi/enable-csd-in-gnome-terminal-2gmm</link>
      <guid>https://dev.to/ikalnytskyi/enable-csd-in-gnome-terminal-2gmm</guid>
      <description>&lt;p&gt;Client-side decoration (&lt;a href="https://wiki.gnome.org/Initiatives/CSD"&gt;CSD&lt;/a&gt;) is the concept of allowing a graphical application software to be responsible for drawing its own window decorations, historically the responsibility of the window manager. GNOME applications is slowly migrating to client-side decoration. While some applications use CSD by default, others draw them only while running in GNOME session.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kQu8G8f0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://kalnytskyi.com/posts/gnome-terminal-csd/headerbar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kQu8G8f0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://kalnytskyi.com/posts/gnome-terminal-csd/headerbar.png" alt="gnome-terminal with csd" width="880" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, CSD is not used by GNOME Terminal if you launch it outside of GNOME session. Fortunately, there's a configuration option you can use to explicitly enable it. In order to do that just run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gsettings set org.gnome.Terminal.Legacy.Settings headerbar true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The setting won't be applied as long as there's a running copy of&lt;code&gt;gnome-terminal-server&lt;/code&gt; process. You have to terminate it and restart the terminal.&lt;/p&gt;

&lt;p&gt;The configuration option is tested with &lt;code&gt;gnome-terminal 3.40&lt;/code&gt;. It might or might not work with other versions.&lt;/p&gt;

</description>
      <category>gnome</category>
      <category>terminal</category>
      <category>csd</category>
    </item>
  </channel>
</rss>
