<?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: Andrea Giacobino</title>
    <description>The latest articles on DEV Community by Andrea Giacobino (@noandrea).</description>
    <link>https://dev.to/noandrea</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%2F188502%2F7547dee0-207e-44a3-be53-033e39dde312.jpeg</url>
      <title>DEV Community: Andrea Giacobino</title>
      <link>https://dev.to/noandrea</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/noandrea"/>
    <language>en</language>
    <item>
      <title>geo2tz - 4 years later</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Sun, 30 Jun 2024 23:12:00 +0000</pubDate>
      <link>https://dev.to/noandrea/geo2tz-4-years-later-61f</link>
      <guid>https://dev.to/noandrea/geo2tz-4-years-later-61f</guid>
      <description>&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; after 4y, the projects have been substantially updated and it is now well-tested and mature.&lt;/p&gt;

&lt;p&gt;In July 2020, I &lt;a href="https://dev.to/noandrea/ready-self-hosted-geo-to-timezone-service-1ee0"&gt;wrote on this platform&lt;/a&gt; about &lt;a href="https://github.com/noandrea/geo2tz"&gt;geo2tz&lt;/a&gt;, a rest API to retrieve the timezone from latitude and longitude coordinates.&lt;/p&gt;

&lt;p&gt;I have sporadically updated the project from time to time, and now, four years later, something has happened that moved me to give it some love and make sure it is up to date, this led to a complete rewrite of the engine that powers it, and this post is about what are the reasons and what are the results of this rewrite.&lt;/p&gt;

&lt;p&gt;When I published the project in 2020, I was working on another project, and I needed something like geo2tz, but I could not find anything that fit my requirements, so I decided to create it by putting together a web framework, the timezone data and a library that was providing the logic to process and query the timezones GeoJson, and that was it.&lt;/p&gt;

&lt;p&gt;Fast forward to the beginning of 2023, I get an &lt;a&gt;issue open&lt;/a&gt; of a person complaining about a set of coordinates missing, but it looked like it was a dataset issue, so there was nothing much to do. But at the beginning of 2024, someone pointed out that the service was not working properly for other coordinates. &lt;/p&gt;

&lt;p&gt;Clearly, something was afoul, and since there were people who took the time to comment, I took it more seriously to check what was going on. What I found out is that the issues were coming from the library that I was using to manage the timezone data, the library stopped being updated and was actually returning incorrect results. &lt;/p&gt;

&lt;p&gt;I took my sweet time to do it, not gonna lie, but eventually, I rewrote the GeoJSON parser, re-engineered the index and algorithm to match the timezone from coordinates, and added a lot of tests to make sure that geo2tz behaves correctly and here we have, a new shiny version (&lt;a href="https://github.com/noandrea/geo2tz/releases/tag/v2.4.0"&gt;2.4.0&lt;/a&gt;) that is ready to put to use! &lt;/p&gt;

</description>
      <category>timezone</category>
      <category>go</category>
      <category>rest</category>
    </item>
    <item>
      <title>Rust + Wasm + Tailwind + Svelte</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Sun, 03 Jan 2021 20:49:05 +0000</pubDate>
      <link>https://dev.to/noandrea/rust-wasm-tailwind-svelte-2kgh</link>
      <guid>https://dev.to/noandrea/rust-wasm-tailwind-svelte-2kgh</guid>
      <description>&lt;p&gt;For this winter lockdown season I took some time to learn Rust and to pack it up with WASM, Tailwind and Svelte. The big absent tech here is TypeScript, but there is already a lot to unpack. &lt;/p&gt;

&lt;p&gt;This post is about the experience of building the &lt;a href="https://thecostof.life/"&gt;CostOf.Life&lt;/a&gt; project from scratch using the tech stack in the title (the sources for everything is provided in the project website). &lt;/p&gt;

&lt;p&gt;CostOf.Life is a command line client and a web interface to model your personal finance over time by giving it a daily cost perspective.&lt;/p&gt;

&lt;h2&gt;
  
  
  Number #1: Rust
&lt;/h2&gt;

&lt;p&gt;I have been exposed to rust for a couple of years by now, working alongside &lt;a href="https://twitter.com/jsnewby"&gt;John&lt;/a&gt; and making a few (unsuccessful) tries to start a project myself.&lt;/p&gt;

&lt;p&gt;Finally I made the step to read the &lt;a href="https://doc.rust-lang.org/book/"&gt;rust book&lt;/a&gt; and boy was it worth it. I mean, Rust is the &lt;a href="https://en.wikipedia.org/wiki/Dark_Souls"&gt;Dark Soul&lt;/a&gt; of modern programming languages, not because it is intrinsically difficult, but because how unforgiving the compiler is. &lt;/p&gt;

&lt;p&gt;Turns out that I have now joined the chorus of the ones singing Rust praises: once you get the theoretical basis it is a joy to work with it and you start to really appreciate the compiler (and especially its suggestions); plus you get a memory safe language with no garbage collection&lt;sup id="fnref1"&gt;1&lt;/sup&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Number #2: WebAssembly (Wasm)
&lt;/h2&gt;

&lt;p&gt;This was a big one also driving the choice of using Rust in the first place, Rust is one of the language that has embraced WebAssembly the most (just search &lt;a href="https://github.com/search?q=wasm"&gt;Wasm in GitHub&lt;/a&gt;) plus the &lt;a href="https://github.com/rustwasm/wasm-pack"&gt;tools&lt;/a&gt; to work with Rust+Wasm are just amazing. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/paritytech"&gt;Parity&lt;/a&gt; has done a lot of work with Rust+Wasm, &lt;a href="https://cosmos.network/"&gt;Cosmos&lt;/a&gt; &lt;a href="https://github.com/CosmWasm/cosmwasm"&gt;smart contracts&lt;/a&gt; are are written in Rust+Wasm, and a quick search for &lt;a href="https://www.npmjs.com/search?q=wasm"&gt;npmjs&lt;/a&gt; shows that it's very popular with crypto stuff commonly used in blockchain tech   (fyi I work with &lt;a href="https://apeunit.com"&gt;Ape Unit&lt;/a&gt; a blockchain consulting agency in Berlin).&lt;/p&gt;

&lt;p&gt;So what about it? The current most popular usage of Wasm (end of 2020) seems to be for &lt;a href="https://www.infoq.com/news/2019/10/WebAssembly-wasm-malicious-usage/"&gt;malicious purposes&lt;/a&gt;. As I see it, for 99% of use cases for common web purposes Wasm is just not necessary, plus it's not so easily integrated (see point #4) so for the moment I am skeptic about adoption beside the crypto nice. &lt;/p&gt;

&lt;h2&gt;
  
  
  Number #3: Tailwind
&lt;/h2&gt;

&lt;p&gt;As I mentioned there is a &lt;a href="https://thecostof.life"&gt;web interface&lt;/a&gt; for the subject project. I am definitely not a visual person, I cannot put together a website to save my life! &lt;/p&gt;

&lt;p&gt;But then &lt;a href="https://twitter.com/ricricucit"&gt;Enrico&lt;/a&gt; (that does that for a living), recommended to drop any fancy idea and just stick with &lt;a href="https://tailwindcss.com/"&gt;tailwindcss&lt;/a&gt; and I have never looked back (it is that great).&lt;/p&gt;

&lt;h2&gt;
  
  
  Number #4: Svelte
&lt;/h2&gt;

&lt;p&gt;If you are an adult in 2020 chances are that you know about &lt;a href="https://en.wikipedia.org/wiki/Game_of_Thrones"&gt;Game of Thrones&lt;/a&gt; and web frameworks are like characters in the serie, there are many but few survive. &lt;/p&gt;

&lt;p&gt;So we still have &lt;a href="https://angular.io/"&gt;Angular&lt;/a&gt; for some reason I don't know, then &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;, the current king (&lt;a href="https://gameofthrones.fandom.com/wiki/Joffrey_Baratheon"&gt;Joffrey&lt;/a&gt; I guess ¯_(ツ)_/¯) and what you &lt;strong&gt;must&lt;/strong&gt; choose when outsourcing, &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt; the underdog and &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; the snobby one.&lt;/p&gt;

&lt;p&gt;I end up choosing Svelte: it is my first experience with any web frameworks and I must say that I have enjoyed very much working with Svelte + Tailwind + Rollup, but again, I am very novice in the field so not very relevant. &lt;/p&gt;

&lt;h2&gt;
  
  
  Putting all together
&lt;/h2&gt;

&lt;p&gt;Building rust command line client, the rust library and building + testing + publishing the wasm npm package was a breeze. Fantastic &lt;a href="https://github.com/rustwasm"&gt;tooling&lt;/a&gt;, super easy and straightforward.&lt;/p&gt;

&lt;p&gt;Building the web app with Svelte + Tailwindcss also quite easy, the project is not very simple but anyway a nice de experience.&lt;/p&gt;

&lt;p&gt;And now the ugly: I could not manage to actually use the published &lt;a href="https://www.npmjs.com/package/costoflife"&gt;wasm package&lt;/a&gt; with Svelte. &lt;/p&gt;

&lt;p&gt;There are some &lt;a href="https://github.com/noandrea/costoflife.ui/issues/1"&gt;issues&lt;/a&gt; with rollup/webpack and wasm that I could not overcome. &lt;/p&gt;

&lt;p&gt;But worthwhile are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rust+Wasm lib: &lt;a href="https://github.com/noandrea/costoflife-rs"&gt;https://github.com/noandrea/costoflife-rs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Wasm testing: &lt;a href="https://github.com/noandrea/costoflife-rs/blob/f64d73e1618d1862f7fb96ea8c82c58398bfa8b4/src/lib.rs#L479"&gt;1&lt;/a&gt;, &lt;a href="https://github.com/noandrea/costoflife-rs/blob/f64d73e1618d1862f7fb96ea8c82c58398bfa8b4/Makefile#L47"&gt;2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Rollup+Tailwind: &lt;a href="https://github.com/noandrea/costoflife.ui/tree/master"&gt;https://github.com/noandrea/costoflife.ui/tree/master&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And of course, the &lt;a href="https://thecostof.life"&gt;CostOf.Life&lt;/a&gt; project. &lt;/p&gt;

&lt;p&gt;I am sure in the following months the issues that prevent this experiment to be successful will be resolved,  I would love to contribute to that but my knowledge in the field is not enough, but if you can and have the will, I would be thrilled to know your opinion on the matter!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;I come from a Java background and I work mostly in Golang ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>rust</category>
      <category>webassembly</category>
      <category>svelte</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Get the upstream distro name in Rust</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Wed, 26 Aug 2020 14:58:08 +0000</pubDate>
      <link>https://dev.to/noandrea/get-the-upstream-distro-name-in-rust-39dm</link>
      <guid>https://dev.to/noandrea/get-the-upstream-distro-name-in-rust-39dm</guid>
      <description>&lt;p&gt;The other day we were chatting with a colleague of mine about retrieving the OS name of the distribution. I don't recall exactly the details, but it was something about always getting the actual distribution name and not the upstream one, and he could not sort that out (I have my suspicions that he didn't try very hard). &lt;/p&gt;

&lt;p&gt;Fast forward 2 weeks, I'm sipping coffee and installing updates on my laptop and suddenly this appears on the screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eZjH-5Si--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uuky7819jfa7x785r2j3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eZjH-5Si--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uuky7819jfa7x785r2j3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh, that's interesting 🤔, let's google "rust distribution id_like"? &lt;a href="https://lmgtfy.com/?q=rust+distribution+id_like"&gt;LMGTFY&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;BOOM! first result: &lt;a href="https://docs.rs/os-release/0.1.0/os_release/struct.OsRelease.html"&gt;https://docs.rs/os-release/0.1.0/os_release/struct.OsRelease.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks good, let's give it a try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; cargo new guess_os
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;guess_os 
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; cargo add os-release
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; vim src/main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;very well now let's add the code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;os_release&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;os_release&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;OsRelease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;OsRelease&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You say '{}', I say '{}'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="py"&gt;.id_like&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now the moment of truth 🥁&lt;/p&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/356037"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vkaUM_J5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://asciinema.org/a/356037.svg" alt="asciicast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🏆&lt;/p&gt;

</description>
      <category>rust</category>
      <category>linux</category>
    </item>
    <item>
      <title>Go vs Py</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Fri, 07 Aug 2020 10:52:22 +0000</pubDate>
      <link>https://dev.to/noandrea/go-vs-py-419o</link>
      <guid>https://dev.to/noandrea/go-vs-py-419o</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Comparing Go and Python for code execution time, working with Docker images  and native packages distribution.&lt;/p&gt;




&lt;p&gt;Recently I was working on a programming challenge and I thought it would be interesting to have an implementation both in Go and Python. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The challenge&lt;/strong&gt; consists of processing a  dataset (specifically a csv of ~100mb), make some aggregations and output a json file that will be used as a data-source to serve a bunch of REST API endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are we comparing?
&lt;/h3&gt;

&lt;p&gt;But enough with the chit-chat, lets dig in about the comparison. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution time&lt;/strong&gt;: time difference in speed between the two implementations to execute the data aggregation algorithm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker image&lt;/strong&gt;: complexity in producing a docker image and size of the generated images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Native distribution&lt;/strong&gt;: ease of use to install and run the app in a native environment (aka on your laptop).&lt;/p&gt;

&lt;h3&gt;
  
  
  A bit of context
&lt;/h3&gt;

&lt;p&gt;Both app are available on github, &lt;a href="https://github.com/noandrea/plz" rel="noopener noreferrer"&gt;here&lt;/a&gt; the Go version and &lt;a href="https://github.com/noandrea/plzPy" rel="noopener noreferrer"&gt;here&lt;/a&gt; the Python one.&lt;/p&gt;

&lt;p&gt;Specifically we'll be comparing &lt;a href="https://github.com/noandrea/plz/releases/tag/v0.2.1" rel="noopener noreferrer"&gt;PLZ Go v0.2.1&lt;/a&gt; with &lt;a href="https://github.com/noandrea/plzPy/releases/tag/v0.1.3" rel="noopener noreferrer"&gt;PLZ Py v0.1.3&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The Go and Python version are respectively &lt;code&gt;go-1.13.8&lt;/code&gt; and &lt;code&gt;python-3.8.5&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Both implementation are quite small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PLZ Go: &lt;strong&gt;250&lt;/strong&gt;loc&lt;/li&gt;
&lt;li&gt;PLZ Py: &lt;strong&gt;191&lt;/strong&gt;loc  (~23% smaller)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Metrics generated with &lt;a href="https://github.com/XAMPPRocky/tokei" rel="noopener noreferrer"&gt;tokei&lt;/a&gt; using: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for Go &lt;code&gt;tokei -f -t=Go -e="*_test.go&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;for Py &lt;code&gt;tokei -f -t=Python -e="tests"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Criteria #1: Execution speed
&lt;/h1&gt;

&lt;p&gt;Both implementations use the same identical sequential algorithm to process the data and both input and output are the same. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmwqvc664vvtzakc0cby7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmwqvc664vvtzakc0cby7.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Average speed&lt;sup id="fnref1"&gt;1&lt;/sup&gt; to process ~100mb csv input to a 32k json ouput is:&lt;/p&gt;

&lt;p&gt;PZL Go: ~0.6s (~2.2x faster)&lt;br&gt;
PLZ Py: ~1.3s&lt;/p&gt;

&lt;p&gt;The algorithm implementation is in the &lt;code&gt;massage&lt;/code&gt; function: &lt;a href="https://github.com/noandrea/plzPy/blob/v0.1.3/plzpy/plzpy.py#L41" rel="noopener noreferrer"&gt;here in v0.1.3 for Python&lt;/a&gt; and &lt;a href="https://github.com/noandrea/plz/blob/v0.2.1/cmd/massage.go#L40" rel="noopener noreferrer"&gt;here in v0.2.1 for Go&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you dig into the code and you spot some evident problem affecting the performance please let me know in the comments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not much to say here, Go is twice faster than Python in this scenario.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best&lt;/strong&gt;: Go &lt;/p&gt;

&lt;h1&gt;
  
  
  Criteria #2: Docker image
&lt;/h1&gt;

&lt;p&gt;Since the application provides a REST API to serve the results of the aggregation, it make sense to ship the app as a Docker image. &lt;/p&gt;

&lt;p&gt;The approach to build the docker image is to use a multi-stage build: first build the app and aggregate the data and then assemble a "production" image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzj5mz0ny4vfc051vqzmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzj5mz0ny4vfc051vqzmv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this criteria Go is hands down the best, you can instruct the compiler to build a self contained binary to be package in a &lt;a href="https://hub.docker.com/_/scratch/" rel="noopener noreferrer"&gt;scratch&lt;/a&gt; image for a &lt;a href="https://hub.docker.com/r/noandrea/plz/tags" rel="noopener noreferrer"&gt;resulting image&lt;/a&gt; size of little more of 9mb (3.5mb compressed). &lt;/p&gt;

&lt;p&gt;On the other, with Python, the final &lt;a href="https://hub.docker.com/r/noandrea/plzpy/tags" rel="noopener noreferrer"&gt;image&lt;/a&gt; (based on &lt;code&gt;3.8-slim-buster&lt;/code&gt;) is a staggering 175mb (55mb compressed). This is due to the many layers that compose the &lt;code&gt;3.8-slim-buster&lt;/code&gt; base image, therefore there is room for improvement by building a custom image, but that will likely require a significant effort for build and maintenance.&lt;/p&gt;

&lt;p&gt;PZL Go: ~9.3mb - (18x smaller)&lt;br&gt;
PLZ Py: ~175mb &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best&lt;/strong&gt;: Go&lt;/p&gt;

&lt;h1&gt;
  
  
  Criteria #3: Native distribution
&lt;/h1&gt;

&lt;p&gt;By native distribution I mean to install the app on a server or on your laptop without having to tinker too much with &lt;em&gt;software requirements&lt;/em&gt;. I strongly believe that this is an important metric, since having complex installation procedures involves a lot of cognitive effort that is ultimately wasted. &lt;/p&gt;

&lt;p&gt;In this area both Go and Python are more or less equivalent on the surface, with Go you can install the package running &lt;code&gt;go get github.com/noandrea/plz&lt;/code&gt; and with Python using &lt;code&gt;pip install plzpy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A caveat is that Python is far more popular and get shipped by default with many OS, while for Go you will likely have to download and install the Go toolkit.&lt;/p&gt;

&lt;p&gt;Another notable difference is that with &lt;code&gt;pip install&lt;/code&gt; you are installing a "binary" distribution while with &lt;code&gt;go get&lt;/code&gt; you are fetching the source code and compiling it locally. &lt;/p&gt;

&lt;p&gt;Worth mentioning that the maintainer(s) of the Go package may have shipped binaries for the OS specific architectures and package managers (&lt;code&gt;brew&lt;/code&gt;, &lt;code&gt;dnf&lt;/code&gt;, &lt;code&gt;apt&lt;/code&gt;, ...), but that requires additional work and maintenance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slightly better&lt;/strong&gt;: Python&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this comparison as much as I did in making it, and about which one is better, Go or Python, the answer is ....🥁  ... both and none 😉! &lt;/p&gt;

&lt;p&gt;👋&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;consistent over multiple executions ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>go</category>
      <category>python</category>
      <category>docker</category>
    </item>
    <item>
      <title>Terminal split-screen recording with asciinema + screen</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Sun, 19 Jul 2020 19:11:38 +0000</pubDate>
      <link>https://dev.to/noandrea/terminal-split-screen-recording-with-asciinema-screen-3b7i</link>
      <guid>https://dev.to/noandrea/terminal-split-screen-recording-with-asciinema-screen-3b7i</guid>
      <description>&lt;p&gt;While showcasing &lt;a href="https://dev.to/noandrea/ready-self-hosted-geo-to-timezone-service-1ee0"&gt;geo2tz&lt;/a&gt; I wanted to record both client and server on the same &lt;a href="https://asciinema.org/~noandrea"&gt;asciinema&lt;/a&gt; video.  &lt;/p&gt;

&lt;p&gt;Luckily you can do just that using &lt;a href="https://linux.die.net/man/1/screen"&gt;screen&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm assuming at this point that you have installed both &lt;code&gt;asciinema&lt;/code&gt; and &lt;code&gt;screen&lt;/code&gt; and that you are on linux.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Before you start&lt;/strong&gt;, add this line &lt;code&gt;layout save default&lt;/code&gt; in your &lt;code&gt;~/.screenrc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next setup your screen session so when you are about to record the screen will be already set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;screen -R devto 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once there execute this sequence of keystrokes (case sensitive): &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; + &lt;code&gt;S&lt;/code&gt; // split horizontally&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; + &lt;code&gt;Tab&lt;/code&gt; // move to the bottom window&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; + &lt;code&gt;c&lt;/code&gt; // open a new shell&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; + &lt;code&gt;Tab&lt;/code&gt; // move back to the top window&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; + &lt;code&gt;d&lt;/code&gt; // detach (but not close) the session&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;pro tip, for maximum effect you can set the windows name with &lt;code&gt;ctrl&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt; + &lt;code&gt;A&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that the stage is ready you can start recording:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;asciinema rec -c "screen -R devto"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here is how it looks like: &lt;/p&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;if you don't see the embed, follow &lt;a href="https://asciinema.org/a/346460"&gt;this link&lt;/a&gt; to the video.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Do you know another way of doing this, maybe with tmux?&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>screenrecording</category>
      <category>shell</category>
    </item>
    <item>
      <title>Self-hosted Geo to Timezone service</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Wed, 08 Jul 2020 20:30:36 +0000</pubDate>
      <link>https://dev.to/noandrea/ready-self-hosted-geo-to-timezone-service-1ee0</link>
      <guid>https://dev.to/noandrea/ready-self-hosted-geo-to-timezone-service-1ee0</guid>
      <description>&lt;p&gt;For the &lt;a href="https://meetvalis.com"&gt;VALIS&lt;/a&gt; project I needed a geo to timezone service, specifically to pick up a reasonable time to send chat messages. &lt;/p&gt;

&lt;p&gt;There are a &lt;a href="https://stackoverflow.com/questions/16086962/how-to-get-a-time-zone-from-a-location-using-latitude-and-longitude-coordinates"&gt;few hosted services&lt;/a&gt; that can do that for you, but I believe that privacy is a feature, and I am not comfortable with sharing location data with 3rd party services.&lt;/p&gt;

&lt;p&gt;A geo to timezone service is a simple service to implement, especially since the heavy stuff 💪 has been already implemented by better human beings 🙏 (the link above also lists the libraries).&lt;/p&gt;

&lt;p&gt;And so here it is: &lt;a href="https://github.com/noandrea/geo2tz"&gt;geo2tz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is how to run and how to interact with it :&lt;/p&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;if you don't see the embedded video, follow this &lt;a href="https://asciinema.org/a/346197"&gt;link&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ps. docker images are hosted on &lt;a href="https://github.com/noandrea/geo2tz/pkgs/container/geo2tz"&gt;gcr&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>privacy</category>
      <category>api</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>Build a demo dataset for your product</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Wed, 17 Jun 2020 10:42:14 +0000</pubDate>
      <link>https://dev.to/apeunit/build-demo-dataset-for-your-product-4575</link>
      <guid>https://dev.to/apeunit/build-demo-dataset-for-your-product-4575</guid>
      <description>&lt;p&gt;I am working on a new product (btw it's name is &lt;a href="https://meetvalis.com"&gt;VALIS&lt;/a&gt;) and we needed a fake dataset to showcase the product and it's functionalities, here some suggestion if you have to do the same&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start from a real world scenario that you know and you are familiar with&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Faking stuff is hard, better to stick with what you know and experience directly: take the data from your personal or work life and use to create the canvas for your demo dataset, next you'll replace names and other details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make it familiar for your audience&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Who is your audience? Are they young? Is gender relevant? You probably already have a good idea about that if your are building a product, keep this in mind when choosing the actors in your dataset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep it as straightforward as possible&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goal of your demo dataset is to showcase your product, not your demo dataset, try to make evident what is what: for example, use well known identifiers for companies (LLC, Inc, ...), locations (City, Lake, ... ), projects, etc. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About using existing brands&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Trademarks are a complicated issue, it may be fine to use existing brands or it may not, &lt;a href="https://coveryourassetsonline.com/can-i-mention-famous-brands-products-or-popular-fictional-characters-in-my-marketing-copy/"&gt;treat with care&lt;/a&gt;. When not sure, don't: better to avoid to recreate your demo and material because of trademark infringement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The holy grail: tailored demo data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Can you think of a way of generating tailored demo data? maybe processing publicly available info from Wikipedia, GitHub or Crunchbase? Then go for it, showcasing a product using your client data will be way more effective than using unknown or fake data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about well known dataset?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It depends, well known for who? If your are not 100% sure that your audience is familiar with a topic is safer to assume that they are not. &lt;/p&gt;

&lt;p&gt;And since your are here, check out &lt;a href="https://meetvalis.com"&gt;VALIS&lt;/a&gt;!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;it doesn't apply for every type of project 😉  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>product</category>
      <category>demo</category>
      <category>dataset</category>
    </item>
    <item>
      <title>From HackMD to PDF</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Sat, 09 May 2020 08:42:49 +0000</pubDate>
      <link>https://dev.to/apeunit/from-hackmd-to-pdf-36n6</link>
      <guid>https://dev.to/apeunit/from-hackmd-to-pdf-36n6</guid>
      <description>&lt;p&gt;Full disclosure, I'm a big fan of Markdown, and also a big fan of &lt;a href="https://hackmd.io" rel="noopener noreferrer"&gt;HackMD&lt;/a&gt; (and it's community fork &lt;a href="https://codimd.org" rel="noopener noreferrer"&gt;CodiMD&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;Now imagine you have to write a technical assessment or specifications and you started writing it down on hackmd/codimd because, you know, reasons 😤. But then, for the sake of the argument, let's say that you have to produce a deliverable artifact that can be shipped to someone, like a customer; then a link to a online document might just not cut it 🤔. &lt;/p&gt;

&lt;p&gt;So what to do? Alright, easy solution, fire up &lt;a href="https://typora.io/" rel="noopener noreferrer"&gt;typora&lt;/a&gt; (or similar), paste the markdown, File &amp;gt; Export &amp;gt;  PDF. The day is saved.&lt;/p&gt;

&lt;p&gt;You go back skimming through the news and you find this: &lt;a href="https://keleshev.com/my-book-writing-setup/" rel="noopener noreferrer"&gt;Writing a Book with Pandoc, Make, and Vim&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait a second... what if... 🤯 &lt;code&gt;vim Makefile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AU_HACKMD_CODE  = bfScafhcTdGzzhJ4B3evlQ
AU_FONT         = NeufileGrotesk
AU_FONT_DIR     = $(HOME)/.fonts/NeufileGrotesk
AU_OUTFILE      = $(HOME)/$(AU_HACKMD_CODE).MD.$(shell date +%F).pdf
AU_FORMAT       = article

hackmd2pdf:
    @echo format doc
    curl -s -L "https://hackmd.io/$(AU_HACKMD_CODE)/download" -o /tmp/$(AU_HACKMD_CODE).md
    pandoc /tmp/$(AU_HACKMD_CODE).md -o $(AU_OUTFILE) \
  --table-of-contents \
  --pdf-engine=xelatex \
  --highlight-style=monochrome \
  --number-sections \
  -H $(HOME)/.config/apeunit/header-$(AU_FORMAT).tex \
  -V 'mainfont:$(AU_FONT)' \
  -V 'mainfontoptions:Extension=.otf, UprightFont=*-MediumExtended, BoldFont=*-BoldExtended, ItalicFont=*-MediumExtendedItalic, BoldItalicFont=*-BoldExtendedItalic, Path=$(AU_FONT_DIR)/' \
  -V 'fontsize: 12pt' \
  -V 'papersize: A4' \
  -V 'urlcolor: blue' \
  -V 'date: \today{}' \
  -V 'documentclass: $(AU_FORMAT)' \
  -V 'geometry:margin=3.8cm'
    xdg-open $(AU_OUTFILE)
    @echo done

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make hackmd2pdf HACKMD_CODE=bfScafhcTdGzzhJ4B3evlQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BOOM!&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Now, I do understand that from a pure aesthetic point of view this might not be enough to satisfy the sensitive eye of the graphic designer, but it can be shipped!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxg70n92dmnw8wg5cueuz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxg70n92dmnw8wg5cueuz.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;some dependencies need to be installed, on ubuntu &lt;code&gt;texlive-xetex&lt;/code&gt; and &lt;code&gt;pandoc&lt;/code&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;this command will not work for you, because it contains specific branding stuff from &lt;a href="https://apeunit.com" rel="noopener noreferrer"&gt;Ape Unit&lt;/a&gt;, but if you are looking for a simpler one, look &lt;a href="https://gist.github.com/noandrea/1082b6649d526d301980b97365691b1c" rel="noopener noreferrer"&gt;no further&lt;/a&gt;! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>latex</category>
      <category>markdown</category>
      <category>pandoc</category>
      <category>pdf</category>
    </item>
    <item>
      <title>GitHub is now free for teams 🤔 </title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Tue, 14 Apr 2020 21:59:46 +0000</pubDate>
      <link>https://dev.to/apeunit/github-is-now-free-for-teams-4e2n</link>
      <guid>https://dev.to/apeunit/github-is-now-free-for-teams-4e2n</guid>
      <description>&lt;p&gt;Today GitHub &lt;a href="https://github.blog/2020-04-14-github-is-now-free-for-teams/"&gt;announced&lt;/a&gt; that you don't need a payed plan anymore to have private repositories for teams. &lt;br&gt;
That is a big announcement and the first thought goes to the competing service, &lt;a href="https://gitlab.com"&gt;GitLab&lt;/a&gt;, that has been offering the same since the very beginning.&lt;/p&gt;

&lt;p&gt;But this is somewhat also an interesting announcement that might have implications for the open source movement in general. Of course &lt;strong&gt;this is just a pure speculation&lt;/strong&gt;, but anyway let's roll with it. &lt;/p&gt;

&lt;p&gt;I think GitHub has been one of the organization that made the "Free for open source" business model popular. The "Free for open source" model works like this: you can use our service free of charge and we get back advertisement and feed our &lt;a href="https://en.wikipedia.org/wiki/Word-of-mouth_marketing"&gt;WOM&lt;/a&gt; marketing. Now developers (and companies) tend to be jealous/shy/protective toward their code, but they are also a pragmatical bunch: subscribing to a payed plan for my weekend-long side project or my hello world flutter might not be something worth doing. &lt;br&gt;
But one thing about open source is that, like most thing, is a quantitative issue more then a qualitative one: once you get used to have your stuff open source, it becomes quite liberating (and, who knows, could even help you land a job). We can say that GitHub with its model has, at the very least, encouraged and promoted the open source software experience. &lt;/p&gt;

&lt;p&gt;Microsoft on the other hand has &lt;a href="https://www.theregister.co.uk/2001/06/02/ballmer_linux_is_a_cancer/"&gt;historically&lt;/a&gt; been the fiercest enemy of the &lt;a href="https://en.wikipedia.org/wiki/Open-source-software_movement"&gt;Open Source Movement&lt;/a&gt;. Microsoft, since 2018, &lt;a href="https://news.microsoft.com/2018/06/04/microsoft-to-acquire-github-for-7-5-billion/"&gt;owns&lt;/a&gt; GitHub, and, with this last move, if you are one of those suspicious people, you might think that they kind of want you not to think too much about all this OSS business: get your free proprietary repository and off you go. &lt;/p&gt;

&lt;p&gt;Also &lt;a href="http://pedrocr.pt/text/microsofts-love-of-linux"&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A pensar male si fa peccato, ma spesso ci si azzecca.&lt;/em&gt; - &lt;a href="https://en.wikipedia.org/wiki/Giulio_Andreotti"&gt;Giulio Andreotti&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>opinion</category>
      <category>microsoft</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Self-hosted Jitsi server with authentication</title>
      <dc:creator>Andrea Giacobino</dc:creator>
      <pubDate>Tue, 17 Mar 2020 22:24:44 +0000</pubDate>
      <link>https://dev.to/noandrea/self-hosted-jitsi-server-with-authentication-ie7</link>
      <guid>https://dev.to/noandrea/self-hosted-jitsi-server-with-authentication-ie7</guid>
      <description>&lt;p&gt;March 2021 update: the tutorial is still valid for the current Jitsi version but there are some new settings in the config file that are not up to date&lt;/p&gt;




&lt;p&gt;As the Coronavirus spreads and more and more people are spending time at home, one of the most critical thing for many is to be able to keep in touch with family, friends and colleagues. &lt;/p&gt;

&lt;p&gt;We at &lt;a href="https://apeunit.com"&gt;Ape Unit&lt;/a&gt; are used to remote and distributed work but the current situation meant that it was necessary to go above and beyond....&lt;/p&gt;

&lt;p&gt;As we are involved in open source projects and since we already use &lt;a href="https://jitsi.org"&gt;Jitsi&lt;/a&gt; we opted to deploy an instance of Jitsi to use internally and since there have been a lot of demand on the &lt;a href="https://community.jitsi.org"&gt;Jitsi community forum&lt;/a&gt; about &lt;a href="https://community.jitsi.org/c/install-config"&gt;installation and configuration&lt;/a&gt; here is a step by step tutorial about how to run your own server.&lt;/p&gt;

&lt;p&gt;Once you have completed the tutorial you will have your own Jisti server with authentication enabled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before you start
&lt;/h3&gt;

&lt;p&gt;This tutorial assumes that you have basic knowledge about technical stuff in particular assumes that you are familiar with the linux shell, &lt;code&gt;ssh&lt;/code&gt;, and dns.&lt;/p&gt;

&lt;h3&gt;
  
  
  The costs
&lt;/h3&gt;

&lt;p&gt;The running cost of the setup varies depending on the server choice and the domain, in this case we'll be using a &lt;a href="https://www.hetzner.com/cloud?country=ot"&gt;Hetzner cloud&lt;/a&gt; instance that starts from 2.49€/m &lt;/p&gt;

&lt;p&gt;this being said, let's start!&lt;/p&gt;

&lt;h2&gt;
  
  
  #1. Setup a new server (with Hetzner)
&lt;/h2&gt;

&lt;p&gt;Login (or create an account on Hetzner), then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;go to the &lt;a href="https://console.hetzner.cloud/projects"&gt;Cloud home&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;choose the project you want (usually &lt;code&gt;Default&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Click on &lt;em&gt;ADD SERVER&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;strong&gt;Create a Server&lt;/strong&gt; page make sure to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;select the &lt;strong&gt;Ubuntu 20.04&lt;/strong&gt; as Image (point 2)&lt;/li&gt;
&lt;li&gt;add your public ssh key (point 7)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then click on &lt;em&gt;CREATE &amp;amp; BUY NOW&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you add your ssh key, make sure that it is enable in the ssh configuration of your machine (more on that &lt;a href="https://www.redhat.com/sysadmin/passwordless-ssh"&gt;here&lt;/a&gt;).  If you do not add your ssh key, you'll receive an email with the root password to the server that you will have to change on first login. As a side note, public key authentication is &lt;a href="https://crypto.stackexchange.com/questions/59120/password-vs-public-key-for-authentication"&gt;preferable&lt;/a&gt; then password.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The server creation is going to take a minute or less, once completed take note of the &lt;strong&gt;IP address&lt;/strong&gt; of the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  #2. Point a domain to the newly created server
&lt;/h2&gt;

&lt;p&gt;for this step, we'll assume that you already have a domain registered (you can grab one on &lt;a href="https://namecheap.com"&gt;namecheap&lt;/a&gt;. For this tutorial we will use the domain &lt;code&gt;apeunit.test&lt;/code&gt; for our domain.&lt;/p&gt;

&lt;p&gt;In your domain DNS configuration add the records:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;type: &lt;code&gt;A&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;host: &lt;code&gt;@&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;value: &lt;strong&gt;IP Address&lt;/strong&gt; (from the Hetzner server)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: it might take a few minutes for the DNS to propagate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  #3. Jitsi installation
&lt;/h2&gt;

&lt;p&gt;Now that the server is up and running, let's set it up!&lt;br&gt;
If everything before has been successful you should be able to login to your server using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ssh root@apeunit.test
The authenticity of host 'apeunit.test (10.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:Q1rLmH7vuBalRJGv7sasTJy+ZtS3yOf4A34artGjUI.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'apeunit.test,10.0.0.1' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
root@server:~#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now proceed with Jitsi installation (documentation &lt;a href="https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;First let's make sure that the system is up to date&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt update
apt upgrade -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install nginx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt install nginx -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can add the Jitsi repositories and install the Jitsi components. During the installation, you will be prompted for a domain to use, when it happens enter the domain you choose/registered at #2. The second question you'll be asked is if generate a self signed certificate or provide your own; choose the default (generate a self signed certificate)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'deb https://download.jitsi.org stable/' &amp;gt;&amp;gt; /etc/apt/sources.list.d/jitsi-stable.list
wget -qO -  https://download.jitsi.org/jitsi-key.gpg.key | apt-key add -
apt update &amp;amp;&amp;amp; apt install jitsi-meet -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, lets ask &lt;a href="https://letsencrypt.org/"&gt;let's encrypt&lt;/a&gt; for a certificate for our domain&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify that the installation was successful, open your browser and enter your domain in the address bar, Jitsi should be now up and running.&lt;/p&gt;

&lt;p&gt;Once we have verified that the installation is working properly, it is time to configure the firewall so not to leave your server exposed. For firewall we are going to use &lt;a href="https://en.wikipedia.org/wiki/Uncomplicated_Firewall"&gt;&lt;code&gt;ufw&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ufw allow ssh
ufw allow http 
ufw allow https 
ufw allow 10000/udp
ufw enable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #4 Enable authentication for Jitsi
&lt;/h2&gt;

&lt;p&gt;Enabling the authentication requires only to edit three files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/etc/jitsi/meet/apeunit.test-config.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/prosody/conf.avail/apeunit.test.cfg.lua&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/jitsi/jicofo/sip-communicator.properties&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: for the first two, change the &lt;code&gt;apeunit.test&lt;/code&gt; part of the filename with your domain&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The official documentation for &lt;a href="https://github.com/jitsi/jicofo#secure-domain"&gt;secure domain&lt;/a&gt; explains the details of the changes, but here are the files already configured:&lt;/p&gt;

&lt;p&gt;I've published the changed files here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/noandrea/5ff6b212273af95103996c0e71f0cdf2#file-apeunit-test-config-js"&gt;&lt;code&gt;/etc/jitsi/meet/apeunit.test-config.js&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/noandrea/5ff6b212273af95103996c0e71f0cdf2#file-apeunit-test-cfg-lua"&gt;&lt;code&gt;/etc/prosody/conf.avail/apeunit.test.cfg.lua&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/noandrea/5ff6b212273af95103996c0e71f0cdf2#file-sip-communicator-properties"&gt;&lt;code&gt;/etc/jitsi/jicofo/sip-communicator.properties&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;but they have to be changed according to your domain name, here is how. First set a variable with your domain name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export JITSI_DOMAIN="your_domain.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then update the meet configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl  https://gist.githubusercontent.com/noandrea/5ff6b212273af95103996c0e71f0cdf2/raw/d14979d5b31af324c5823b3d3c8683a6c762f518/apeunit.test-config.js -s | \
sed  "s/apeunit.test/$JITSI_DOMAIN/g" \
&amp;gt; /etc/jitsi/meet/$JITSI_DOMAIN-config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then the prosody configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://gist.githubusercontent.com/noandrea/5ff6b212273af95103996c0e71f0cdf2/raw/d14979d5b31af324c5823b3d3c8683a6c762f518/apeunit.test.cfg.lua -s | \
sed  "s/apeunit.test/$JITSI_DOMAIN/g" | \
sed  "s/JICOFO_SECRET/$(grep -e '^JICOFO_SECRET=.*' /etc/jitsi/jicofo/config | cut -d '=' -f2)/g" | \
sed  "s/TURN_SECRET/$(&amp;lt; /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-8})/g" \
&amp;gt; /etc/prosody/conf.avail/$JITSI_DOMAIN.cfg.lua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and finally the sip communicator properties file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "org.jitsi.jicofo.auth.URL=XMPP:$JITSI_DOMAIN" \
&amp;gt;&amp;gt; /etc/jitsi/jicofo/sip-communicator.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this part is completed it is now time to create your users, with the command &lt;code&gt;prosodyctl register USER DOMAIN PASSWORD&lt;/code&gt;; in our example we can register the user &lt;code&gt;jane&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prosodyctl register jane $JITSI_DOMAIN janepwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Currently there is no option to make users register themselves, you will have to create users by command line. Also not all the users need to have a password, only the ones that open a room. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To apply the changes last thing we have to do is to restart Jitsi services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl restart jicofo
systemctl restart jitsi-videobridge2
systemctl restart prosody
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Now you can enjoy your private chat server thanks to the wonderful &lt;a href="https://jitsi.org"&gt;Jitsi&lt;/a&gt;! &lt;/p&gt;

</description>
      <category>jitsi</category>
      <category>tutorial</category>
      <category>selfhosted</category>
      <category>conferencing</category>
    </item>
  </channel>
</rss>
