<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.7.2">Jekyll</generator><link href="https://www.jakobstoeck.de/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.jakobstoeck.de/" rel="alternate" type="text/html" /><updated>2023-01-15T14:41:05+00:00</updated><id>https://www.jakobstoeck.de/</id><title type="html">Jakob Stoeck</title><author><name>It’s me!</name></author><entry><title type="html">Download and query all domains of the world-wide web</title><link href="https://www.jakobstoeck.de/2023/download-and-query-all-domains-of-the-world-wide-web/" rel="alternate" type="text/html" title="Download and query all domains of the world-wide web" /><published>2023-01-15T01:31:00+00:00</published><updated>2023-01-15T01:31:00+00:00</updated><id>https://www.jakobstoeck.de/2023/download-and-query-all-domains-of-the-world-wide-web</id><content type="html" xml:base="https://www.jakobstoeck.de/2023/download-and-query-all-domains-of-the-world-wide-web/">&lt;p&gt;I was wondering whether I could get a list of all world wide web domains on my local laptop and query them, like a phone book. As it turns out, that is straight-forward: You can download all top-level domains (TLD) zone server zonefiles, then use local tools to search through the less than 10 GB gzipped files.&lt;/p&gt;

&lt;h2 id=&quot;how-to-download&quot;&gt;How to download&lt;/h2&gt;

&lt;p&gt;Since domains are stored online in domain name system (DNS) servers that are reachable by the public, you could use the DNS protocol to request for the full list of domains of each DNS server that is responsible for a top-level domain (like .com). But for security reasons, you cannot request a zonefile from an authoritative DNS server anymore as this would enable an &lt;a href=&quot;https://en.wikipedia.org/wiki/Denial-of-service_attack#Amplification&quot;&gt;amplification denial-of-service attack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That is why the Internet Corporation for Assigned Names and Numbers (ICANN) provided a Centralized Zone Data Service, where any interested party can request and subsequently download nearly all zone files. For the vast majority of the 1,000+ TLD you don’t need a better reason than “for research purposes”, whereas some of the more obscure ones request for more information.&lt;/p&gt;

&lt;p&gt;To download all zonefiles for the as of writing of this post 266,372,902 domains (easy to remember: slightly less domains than &lt;code class=&quot;highlighter-rouge&quot;&gt;c&lt;/code&gt;, the speed of light):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Go to &lt;a href=&quot;https://czds.icann.org/&quot;&gt;https://czds.icann.org/&lt;/a&gt; and register&lt;/li&gt;
  &lt;li&gt;Go to &lt;a href=&quot;https://github.com/icann/czds-api-client-python&quot;&gt;https://github.com/icann/czds-api-client-python&lt;/a&gt;, input your credentials as mentioned in the readme, install dependencies and download:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;czds-api-client-python
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;config&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;.sample,&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;.json
&lt;span class=&quot;c&quot;&gt;# update config.json with your credentials&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pipenv &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;requests
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pipenv run python download.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;how-to-query&quot;&gt;How to query&lt;/h2&gt;

&lt;p&gt;Now, you will have more than 1,000 gzipped text files with all domains. The files are tab-separated. DNS has entry types that mark different purposes: mail servers, name servers (what your browser uses), signatures, etc.&lt;/p&gt;

&lt;p&gt;For example, the first 5 lines of the &lt;code class=&quot;highlighter-rouge&quot;&gt;.pizza&lt;/code&gt; TLD look like this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;zless pizza.txt.gz | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n5&lt;/span&gt;
pizza.	3600	&lt;span class=&quot;k&quot;&gt;in	&lt;/span&gt;soa	v0n0.nic.pizza. hostmaster.donuts.email. 1672103559 7200 900 1209600 3600
0.pizza.	3600	&lt;span class=&quot;k&quot;&gt;in	&lt;/span&gt;ds	27676 8 2 95C9CB61DEF5016F2905C7478044E011AE3C041AEB31E5BC80C11DEE7FC05142
0.pizza.	3600	&lt;span class=&quot;k&quot;&gt;in	&lt;/span&gt;ns	ns-cloud-d1.googledomains.com.
0.pizza.	3600	&lt;span class=&quot;k&quot;&gt;in	&lt;/span&gt;ns	ns-cloud-d2.googledomains.com.
0.pizza.	3600	&lt;span class=&quot;k&quot;&gt;in	&lt;/span&gt;ns	ns-cloud-d3.googledomains.com.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the reason of this project I’m interested in the name servers which are marked with &lt;code class=&quot;highlighter-rouge&quot;&gt;ns&lt;/code&gt; in the fourth column. You see that for the first lines of pizza.txt.gz that is the domain http://0.pizza/ (Which is defunct. What did the owner want to do with that domain? Do they sell pizzas in the shape of a zero with a hole in the middle? We will never know.).&lt;/p&gt;

&lt;p&gt;To get all domains from a name server (the ones your web browser would use), we filter on the fourth column, remove duplicates, and send them to &lt;a href=&quot;https://github.com/junegunn/fzf&quot;&gt;fzf&lt;/a&gt; (on mac: &lt;code class=&quot;highlighter-rouge&quot;&gt;$ brew install fzf&lt;/code&gt;) for fuzzy searching capabilities:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gzcat &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.txt.gz | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\t'&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$4==&quot;ns&quot; { print $1 }'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;uniq&lt;/span&gt; | fzf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Turns out this is fast enough to checkout the data.&lt;/p&gt;

&lt;p&gt;Searching through all domains worldwide instantly is pretty fun! There are so many fun, surprising and head-scratching domain names out there. I hope you find some which excite you!&lt;/p&gt;

&lt;h2 id=&quot;some-observations&quot;&gt;Some observations&lt;/h2&gt;

&lt;h4 id=&quot;people-use-dns-for-much-more-than-i-thought&quot;&gt;People use DNS for much more than I thought.&lt;/h4&gt;

&lt;p&gt;Especially public signatures, see an example from &lt;code class=&quot;highlighter-rouge&quot;&gt;.pizza&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gzcat pizza.txt.gz | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\t'&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{ print $4 }'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;uniq 
&lt;/span&gt;a
aaaa
dnskey
ds
ns
nsec3
nsec3param
rrsig
soa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;there-are-so-many-tlds&quot;&gt;There are so many TLDs!&lt;/h4&gt;

&lt;p&gt;A bit less than 2,000 TLDs, with even local variants like &lt;code class=&quot;highlighter-rouge&quot;&gt;.vermögensberater&lt;/code&gt; (financial advisor). You can lookup the history and raison d’être of each TLD on &lt;a href=&quot;https://icannwiki.org/&quot;&gt;https://icannwiki.org/&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;the-first-domain-was-no&quot;&gt;The first domain was &lt;code class=&quot;highlighter-rouge&quot;&gt;.no&lt;/code&gt;&lt;/h4&gt;

&lt;h4 id=&quot;limitations&quot;&gt;Limitations&lt;/h4&gt;

&lt;p&gt;The zone files do not include subdomains. Some TLDs use third level domain names, like &lt;code class=&quot;highlighter-rouge&quot;&gt;.co.no&lt;/code&gt;. These subdomains are not on the TLD zone server either, and hence not part of this list.
Non-ascii domains are in puny code, and not translated. You would need to convert either your search or the index with something like &lt;a href=&quot;https://pypi.org/project/idna/&quot;&gt;https://pypi.org/project/idna/&lt;/a&gt; or &lt;a href=&quot;https://docs.rs/idna/latest/idna/&quot;&gt;https://docs.rs/idna/latest/idna/&lt;/a&gt;.&lt;/p&gt;</content><author><name>It’s me!</name></author><summary type="html">Query all top level domains (TLD) locally</summary></entry><entry><title type="html">Stuff I used in January 2019</title><link href="https://www.jakobstoeck.de/2019/stuff-i-used-in-january-2019/" rel="alternate" type="text/html" title="Stuff I used in January 2019" /><published>2019-01-02T21:08:00+00:00</published><updated>2019-01-02T21:08:00+00:00</updated><id>https://www.jakobstoeck.de/2019/stuff-i-used-in-january-2019</id><content type="html" xml:base="https://www.jakobstoeck.de/2019/stuff-i-used-in-january-2019/">&lt;p&gt;Quick recap of noteworthy tech stuff I used:&lt;/p&gt;

&lt;h2 id=&quot;1-pipe-tcpdump-from-remote-server-to-local-wireshark&quot;&gt;1. Pipe &lt;code class=&quot;highlighter-rouge&quot;&gt;tcpdump&lt;/code&gt; from remote server to local Wireshark&lt;/h2&gt;

&lt;p&gt;This will show all the traffic from &lt;code class=&quot;highlighter-rouge&quot;&gt;remote&lt;/code&gt; on your local Wireshark application. &lt;code class=&quot;highlighter-rouge&quot;&gt;brew install wireshark&lt;/code&gt; before if you haven’t done, yet:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh username@remote &lt;span class=&quot;s1&quot;&gt;'tcpdump -s0 -nn -w - not port 22'&lt;/span&gt; | wireshark &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See the &lt;code class=&quot;highlighter-rouge&quot;&gt;not port 22&lt;/code&gt; which makes sure to not track your ssh traffic your sending from the remote to the local server.&lt;/p&gt;

&lt;h2 id=&quot;2-csp-content-security-policy&quot;&gt;2. CSP: Content Security Policy&lt;/h2&gt;

&lt;p&gt;A HTTP Header to whitelist script locations so you mitigate &lt;abbr title=&quot;Cross-site scripting&quot;&gt;XSS&lt;/abbr&gt; attacks. See the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&quot;&gt;&lt;abbr title=&quot;Mozilla Developer Network&quot;&gt;MDN&lt;/abbr&gt; Website for details.&lt;/a&gt;, e.g. if you want all your content come from your domain, excluding subdomains, you should send this &lt;abbr title=&quot;Hypertext Transfer Protocol&quot;&gt;HTTP&lt;/abbr&gt; header: &lt;code class=&quot;highlighter-rouge&quot;&gt;Content-Security-Policy: default-src 'self'&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;3-format-javascript-objects-as-json-with-jq&quot;&gt;3. Format JavaScript Objects as JSON with jq&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;jq&lt;/code&gt; can only format JSON but not plain JavaScript objects. To convert the latter to the former I used “relaxed JSON” (&lt;code class=&quot;highlighter-rouge&quot;&gt;rjson&lt;/code&gt;) like this:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;rjson jq
rjson &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;./returnsJavaScriptCmd&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; | jq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;4-draw-diagrams-with-yed&quot;&gt;4. Draw diagrams with yEd&lt;/h2&gt;

&lt;p&gt;It seems that &lt;a href=&quot;https://www.yworks.com/products/yed&quot;&gt;yEd&lt;/a&gt; is the best editor for technical diagrams out there. If not dot files go a long way and there is an easy “&lt;a href=&quot;https://www.graphviz.org/&quot;&gt;GraphViz&lt;/a&gt; for the poor”, i.e. viewing dot files without the graphviz app. It is using the excellent &lt;a href=&quot;http://eradman.com/entrproject/&quot;&gt;entr&lt;/a&gt; to run automatically on file change:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;entr dot
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;myfile.dot | entr &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; dot &lt;span class=&quot;nt&quot;&gt;-Tpdf&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; /tmp/dot_out.pdf /_
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;5-flutter&quot;&gt;5. Flutter&lt;/h2&gt;

&lt;p&gt;Write native Android apps in Dart.&lt;/p&gt;

&lt;h2 id=&quot;6-postgrest&quot;&gt;6. PostgREST&lt;/h2&gt;

&lt;p&gt;Serve a RESTful API from any database with the great &lt;a href=&quot;http://postgrest.org/&quot;&gt;PostgREST.&lt;/a&gt; Death to the &lt;abbr title=&quot;Object Relational Mapping&quot;&gt;ORM&lt;/abbr&gt; and all its business code which is duplicating database structures. Here you use all the power of a great database to build up a &lt;abbr title=&quot;Create Read Update&quot;&gt;CRUD&lt;/abbr&gt; &lt;abbr title=&quot;Apllication Programming Interface&quot;&gt;API&lt;/abbr&gt; including authorization. Declarative programming &lt;abbr title=&quot;For the win&quot;&gt;ftw&lt;/abbr&gt;!&lt;/p&gt;

&lt;h2 id=&quot;7-greensock-animation-platform&quot;&gt;7. GreenSock Animation Platform&lt;/h2&gt;

&lt;p&gt;&lt;abbr title=&quot;GreenSock Animation Platform&quot;&gt;GSAP&lt;/abbr&gt; is professional-grade animation for JavaScript canvas and looks &lt;a href=&quot;https://greensock.com/&quot;&gt;amazing.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;8-jaeger&quot;&gt;8. Jaeger&lt;/h2&gt;

&lt;p&gt;Tracing in distributed systems with &lt;a href=&quot;https://www.jaegertracing.io/&quot;&gt;jaeger.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;9-update-your-private-key&quot;&gt;9. Update your private key&lt;/h2&gt;

&lt;p&gt;If your private key is still in an old or unsecure format, you can update it with:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh-keygen &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; PRIVATE_KEY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;10-business-process-modelling-language&quot;&gt;10. Business Process Modelling Language&lt;/h2&gt;

&lt;p&gt;Model your business process in &lt;abbr title=&quot;Business Process Modelling Language&quot;&gt;BPML&lt;/abbr&gt; instead of writing business logic in code. Old-school tools like &lt;a href=&quot;https://www.activiti.org/&quot;&gt;Activiti&lt;/a&gt; or &lt;a href=&quot;https://www.jbpm.org/&quot;&gt;jPBM&lt;/a&gt; support them and there are also fancy new &lt;strike&gt;unstable&lt;/strike&gt; nodejs packages for it. This makes it easy for your stakeholders to define and change business processes without you having to change that in your code.&lt;/p&gt;</content><author><name>It’s me!</name></author><summary type="html">Quick recap of noteworthy tech stuff I used</summary></entry><entry><title type="html">Don’t demolish</title><link href="https://www.jakobstoeck.de/2018/dont-rewrite/" rel="alternate" type="text/html" title="Don’t demolish" /><published>2018-02-18T13:00:00+00:00</published><updated>2018-02-18T13:00:00+00:00</updated><id>https://www.jakobstoeck.de/2018/dont-rewrite</id><content type="html" xml:base="https://www.jakobstoeck.de/2018/dont-rewrite/">&lt;p&gt;&lt;img src=&quot;/assets/never-demolish.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Transformation de 530 logements, bâtiments G, H, I, quartier du Grand Parc - Lacaton &amp;amp; Vassal, Druot, Hutin, Image © &lt;a href=&quot;mailto:philippe.ruault@numericable.fr&quot;&gt;Philippe Ruault&lt;/a&gt; - For all uses, thank you to contact him&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Much is written about how you should not rewrite a whole application and I have added some further reading at the bottom of this post. Here I want to add some reasons of why you probably landed where you are right now and why a rewrite is just another indicator of your fundamental problems:&lt;/p&gt;

&lt;p&gt;&lt;abbr title=&quot;Too long didn’t read&quot;&gt;TL;DR&lt;/abbr&gt;: Software development teams should solve business problems instead of implementing predetermined solutions, need performance indicators and architectural principles.&lt;/p&gt;

&lt;h2 id=&quot;an-analogy-in-civil-engineering&quot;&gt;An analogy in civil engineering&lt;/h2&gt;

&lt;p&gt;Housing complexes built in Europe during the 1960s and 1970s are largely considered outdated and urbanistically failed. France ruled in 1990 to rebuild them. Until now, the demolition of 113,200 housing units and the relocation of its inhabitants cost 3 billion. Building 105,000 new homes cost 12 billion - a total of 15 billion for a loss of 8,200 homes.&lt;/p&gt;

&lt;p&gt;A couple of architects were offended for economic and social reasons and started to show the government how to renovate instead of demolishing and letting the residents live in their home. There is &lt;a href=&quot;http://ruby-press.com/projects/never-demolish/&quot;&gt;a great exhibition&lt;/a&gt; about it.&lt;/p&gt;

&lt;p&gt;In one example at &lt;a href=&quot;http://lacatonvassal.com/index.php?idp=80&quot;&gt;Cité du Grand Parc in Bordeaux&lt;/a&gt;, three old housing complexes with 4,000 inhabitants were augmented by these architects by adding winter gardens to the front and back extending the living space by one third. Serving as a climate buffer they additionally reduced the house energy consumption by half and added a better working ventilation. The cost came down to half of what a complete rebuild was estimated and renovation was organized in a way to let the residents live inside their homes nearly the whole time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/never-demolish-2.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;The blue winter gardens were added to the structure for more living space and climate buffer, making a demolition and relocation unnecessary, Image © &lt;a href=&quot;https://lacatonvassal.com/index.php?idp=80&quot;&gt;Lacaton &amp;amp; Vassal - Druot&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;back-to-software-engineering&quot;&gt;Back to software engineering&lt;/h2&gt;

&lt;p&gt;So you have a “legacy application” which needs a rewrite. Instead of throwing it away and commencing the rewrite ponder about how it could come so far and whether your current organization is really capable of writing something better.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If your current application is beyond repair in your eyes, the fault most probably lies not within the technology but your organization. Instead of rewriting, think about the prerequisites which are not fulfilled.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;1-product-development-done-wrong&quot;&gt;1. Product development done wrong&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Many software organizations use agile methods nowadays. Agile teams should focus on &lt;em&gt;business problems&lt;/em&gt;. If you don’t let them, they cannot iterate and you just have a badly implemented waterfall team in disguise.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As an example: You have an online shop and too many abandonments before checkout.&lt;/p&gt;

&lt;h4 id=&quot;do-let-the-team-solve-business-problems&quot;&gt;Do: Let the team solve business problems&lt;/h4&gt;

&lt;p&gt;The agile approach is to have an interdisciplinary team e.g. “Customer Journey” and hand them this problem without a solution. Only now is this team in the position to iterate on ever-enhanced solutions: tighten the funnel, make user studies to search for unknown problems, install monitoring, data analysis etc.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Making-sense-of-MVP-5.png&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Henrik Kniberg (2016) &lt;a href=&quot;http://blog.crisp.se/2016/01/25/henrikkniberg/making-sense-of-mvp&quot;&gt;Source&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The team remains active also if there are no current problems which are handed to “Customer Journey”. They just enhance the current state of things: Better monitoring, faster performance, more tests, more data analysis, fix small problems before they become big, etc. Top management sometimes focuses on utilization and thinks this approach is inefficient. This is a fallacy. &lt;a href=&quot;https://martinfowler.com/articles/products-over-projects.html&quot;&gt;You don’t improve the flow of traffic on a highway by improving its utilization (i.e. introducing more vehicles).&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;dont-let-the-team-implement-a-given-solution&quot;&gt;Don’t: Let the team implement a given solution&lt;/h4&gt;

&lt;p&gt;This is different to a lot of organizations where the business and technology leaders come up with a solution beforehand (“The funnel must be shorter”) and let a team implement this. Many organizations using Scrum do this: They are responding to feedback instead of solving problems.&lt;/p&gt;

&lt;p&gt;This is not agile even if you have agile teams. See how the team cannot iterate on the solutions anymore but just on a single predefined solution which might even not accepted until the last iteration. This is a waterfall-y process just much less efficient.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Making-sense-of-MVP-1.png&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Henrik Kniberg (2016) &lt;a href=&quot;https://blog.crisp.se/2016/01/25/henrikkniberg/making-sense-of-mvp&quot;&gt;Source&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are doing this you should not rewrite your application. It will end up the same like the last one. Instead rewrite small parts of it. And try to change the organizational structure to get more into the best practices outlined above.&lt;/p&gt;

&lt;h2 id=&quot;2-performance-indicators-to-improve-are-not-clear&quot;&gt;2. Performance indicators to improve are not clear&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;You must have a strict definition and monitoring of performance indicators. If you don’t then the next application version will have similar business problems like the current one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;do-applications-report-their-status-by-themselves&quot;&gt;Do: Applications report their status by themselves&lt;/h4&gt;

&lt;p&gt;All components should have business monitoring capabilities built-in. Too many errors, checkout abandonments or fluctuations during the current time period? The application itself should report this to a monitoring solution.&lt;/p&gt;

&lt;p&gt;Like this you have much more context information to what is happening. You need this to always be able to enhance parts of the application where needed.&lt;/p&gt;

&lt;p&gt;Your data analysis is much more profound if you have this internal monitoring and changes are seen directly. You allow teams to be creative to improve the given KPIs bit by bit.&lt;/p&gt;

&lt;h4 id=&quot;dont-only-do-external-monitoring&quot;&gt;Don’t: Only do external monitoring&lt;/h4&gt;

&lt;p&gt;If you don’t have extensive monitoring capabilities built into your application which are adapted to your business case but are only monitoring from the outside with some analytics tool you do not have enough insights to rewrite your application.&lt;/p&gt;

&lt;p&gt;It will end with similar shortcomings like the current one. Instead focus on setting clear business goals, carve out parts of your software and organization which optimize this KPI and steadily improve them.&lt;/p&gt;

&lt;h2 id=&quot;3-architecture-principles&quot;&gt;3. Architecture Principles&lt;/h2&gt;

&lt;p&gt;For your problem solving teams to work autonomously and efficiently, your organization needs to commit to architectural principles which are measurable and testable (around ten is a good size). This cuts down on wasted communication around implementation details. Depending on your business these may be different.&lt;/p&gt;

&lt;h4 id=&quot;do-make-teams-adhere-to-architecture-principles&quot;&gt;Do: Make teams adhere to architecture principles&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://theartofscalability.com&quot;&gt;The art of scalability&lt;/a&gt; has a great starting list. Adjust the list to fit your organization. More details can be found in the book (chapter 12), but this should give you a good idea:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Build small, release fast, fail small&lt;/li&gt;
  &lt;li&gt;Design to be monitored&lt;/li&gt;
  &lt;li&gt;Design to be disabled&lt;/li&gt;
  &lt;li&gt;Design to rollback&lt;/li&gt;
  &lt;li&gt;Use mature technologies&lt;/li&gt;
  &lt;li&gt;Buy when non-core&lt;/li&gt;
  &lt;li&gt;Commodity hardware&lt;/li&gt;
  &lt;li&gt;Isolate faults&lt;/li&gt;
  &lt;li&gt;N+1 design&lt;/li&gt;
  &lt;li&gt;Asynchronous design&lt;/li&gt;
  &lt;li&gt;Automation over people&lt;/li&gt;
  &lt;li&gt;Horizontal scaling&lt;/li&gt;
  &lt;li&gt;Design for multiple live sites&lt;/li&gt;
  &lt;li&gt;Stateless systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check new solution concepts from your teams against your architecture principles in a small informal architecture board and give suggestions to fulfill them when needed.&lt;/p&gt;

&lt;h4 id=&quot;dont-let-a-team-overlook-architecture-principles&quot;&gt;Don’t: Let a team overlook architecture principles&lt;/h4&gt;

&lt;p&gt;If each team decides themselves which principles are important you are creating a lot of communication deciding about &lt;em&gt;who&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt; something should be built instead of &lt;em&gt;what&lt;/em&gt; should be built. While the former is inefficient, error-prone and may lead to intra-team fights the latter may be very productive.&lt;/p&gt;

&lt;p&gt;Instead build up architecture principles together with your teams to which each one adheres to.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Teams should solve business problems, need performance indicators and architectural principles. If you don’t have them don’t even think about a rewrite.&lt;/p&gt;

&lt;p&gt;If you do, read on why you still should not rewrite and instead shape the organization and contingent software to improve over time:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/&quot;&gt;Things You Should Never Do, Part I, Joel Spolsky, 2000&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://chadfowler.com/2006/12/27/the-big-rewrite.html&quot;&gt;The Big Rewrite, Chad Fowler, 2006&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://theartofscalability.com&quot;&gt;The Art of Scalability, Michael T. Fisher, Martin L. Abbott, 2015&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.crisp.se/2016/01/25/henrikkniberg/making-sense-of-mvp&quot;&gt;Making sense of MVP (Minimum Viable Product) – and why I prefer Earliest Testable/Usable/Lovable, Henrik Kniberg, 2016&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://martinfowler.com/articles/products-over-projects.html&quot;&gt;Products Over Projects, Sriram Narayan, 2017&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/never-demolish-3.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Before and after augmenting a building using its main structure, Image © &lt;a href=&quot;mailto:philippe.ruault@numericable.fr&quot;&gt;Philippe Ruault&lt;/a&gt; - For all uses, thank you to contact him&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;(Edit 2018-03-07: Added civil engineering analogy and changed title from “rewrite” to “demolish” to make the intent clearer.)&lt;/p&gt;</content><author><name>It’s me!</name></author><summary type="html">Why a software rewrite is not a good solution, what the underlying issues probably are and what you could do instead.</summary></entry><entry><title type="html">Fireside Chat With Joel Spolsky</title><link href="https://www.jakobstoeck.de/2018/fireside-chat-with-joel-spolsky/" rel="alternate" type="text/html" title="Fireside Chat With Joel Spolsky" /><published>2018-01-23T19:43:00+00:00</published><updated>2018-01-23T19:43:00+00:00</updated><id>https://www.jakobstoeck.de/2018/fireside-chat-with-joel-spolsky</id><content type="html" xml:base="https://www.jakobstoeck.de/2018/fireside-chat-with-joel-spolsky/">&lt;p&gt;Just came back from the fireside chat with &lt;a href=&quot;https://www.joelonsoftware.com/&quot;&gt;Joel Spolsky&lt;/a&gt; organized by Stylight’s &lt;a href=&quot;http://romefort.net/&quot;&gt;Johann Romefort&lt;/a&gt; in the co-working space &lt;a href=&quot;https://www.mindspace.me/munich/viktualienmarkt/&quot;&gt;Mindspace&lt;/a&gt; in the vicinity of Munich’s Viktualienmarkt. For those of you who could not attend but are interested these were some of the topics:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/spolsky-fireside-chat.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Mindspace co-working with fireside chat (Jakob Stoeck)&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;evangelists-become-more-important&quot;&gt;Evangelists become more important&lt;/h2&gt;

&lt;p&gt;An ever-increasing amount of smaller companies employ evangelists to push products or services like their API or technology.&lt;/p&gt;

&lt;h2 id=&quot;glitch---learn-to-code&quot;&gt;Glitch - Learn to code&lt;/h2&gt;

&lt;p&gt;A product from Fog Creek which debuted in 2016: &lt;a href=&quot;https://glitch.com/&quot;&gt;Glitch&lt;/a&gt;. A “friendly community where you’ll build the app of your dreams”. Looks fun and is educating beginners about “real programming” (Joel) unlike “dumbed down” children’s apps which just teach you basic concepts. It teaches developing in JavaScript on Node.js with transparent deployment and provisioning so that beginners don’t have to learn how to use git, GitHub, deploy workflows etc. before starting.&lt;/p&gt;

&lt;h2 id=&quot;company-internal-stack-overflow&quot;&gt;Company-internal Stack Overflow&lt;/h2&gt;

&lt;p&gt;Stack Overflow will get a company-internal version which might be on-premise or cloud-hosted. For companies starting around 500 employees you can have your own private Stack Overflow and exchanging questions and answers. A very interesting twist to the ever-outdated wiki or other knowledge solutions.&lt;/p&gt;

&lt;h2 id=&quot;python---fastest-growing-language&quot;&gt;Python - fastest growing language&lt;/h2&gt;

&lt;p&gt;Asked which technology trend might be important in the coming years Joel stated that according to Stack Overflow statistics, Python is the fastest growing language because of many Big Data and ML applications. Nothing new here :)&lt;/p&gt;

&lt;h2 id=&quot;stackexchange-and-stack-overflow&quot;&gt;StackExchange and Stack Overflow&lt;/h2&gt;

&lt;p&gt;The importance of the &lt;a href=&quot;https://stackoverflow.com/dev-survey/start&quot;&gt;2018 developer survey&lt;/a&gt; in the industry is reiterated. Participation especially in Germany is rare. Joel is asking for help and more people taking the survey.&lt;/p&gt;

&lt;p&gt;The answer for the question which community is the most fascinating on StackExchange Joel replied with Math Overflow with discussions ranging qualitatively between a math book and a journal. Seems like most important mathematicians are online and discussing on there. Go on, how many of the &lt;a href=&quot;https://mathoverflow.net/questions&quot;&gt;top questions&lt;/a&gt; do you understand?&lt;/p&gt;

&lt;p&gt;The first user ever in a StackExchange community cracked a reputation of 1 million. Who is it? &lt;a href=&quot;https://stackoverflow.com/users/22656/jon-skeet&quot;&gt;Yes, you’re right.&lt;/a&gt; Living outside of London he is using his commute time five times a week to help the community. Nice! Here, have some &lt;a href=&quot;https://meta.stackexchange.com/questions/9134/jon-skeet-facts/9182#9182&quot;&gt;Jon Skeet Facts.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;outsourcing-and-remote-work&quot;&gt;Outsourcing and remote work&lt;/h2&gt;

&lt;p&gt;Like many people in the industry Joel is no big fan of outsourcing developers. It really just shifts the burden of finding great developer talent to finding a great recruiter who finds great developer talent which might be even harder. In both cases you need to interview the candidates yourself so there isn’t even a time saving.&lt;/p&gt;

&lt;p&gt;That doesn’t mean that you shouldn’t work with people from remote. On the contrary, you should to find exceptional talent. But your whole communication needs to switch to remote, no mix-and-match. If you hold a meeting, it is a remote meeting for everyone. Even if some people are sitting in the same office, they go to their phone booths or private rooms to use the same technology like everyone to make sure that the quality is always high and you don’t have second class citizens communicative-wise. Alternatively pay big sums, but there were some laughs to the last quote:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“If you have some walls then you don’t need to pay so much!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/facebook-office-wp.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Facebook’s headquarters in Menlo Park (Washington Post)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It was a nice little after work meetup with many interesting guests. Thanks again!&lt;/p&gt;</content><author><name>It’s me!</name></author><summary type="html">A summary of the talk in Munich.</summary></entry><entry><title type="html">Open Source Speech To Text App</title><link href="https://www.jakobstoeck.de/2017/ios-speech-to-text-app-thats-what-she-said/" rel="alternate" type="text/html" title="Open Source Speech To Text App" /><published>2017-09-14T07:30:00+00:00</published><updated>2017-09-14T07:30:00+00:00</updated><id>https://www.jakobstoeck.de/2017/ios-speech-to-text-app-thats-what-she-said</id><content type="html" xml:base="https://www.jakobstoeck.de/2017/ios-speech-to-text-app-thats-what-she-said/">&lt;p&gt;Playing a bit with Java and Swift, I built two small apps for iOS and Android and solved a problem of mine: With “That’s What She Said” you receive the text of any voice message without listening to it.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://itunes.apple.com/us/app/thats-what-she-said/id1239469302?ls=1&amp;amp;mt=8&quot;&gt;View on Apple App Store&lt;/a&gt; (&lt;a href=&quot;https://github.com/jakob-stoeck/speechToText&quot;&gt;GitHub&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=de.jakobstoeck.speechtotext&quot;&gt;View on Google Play Store&lt;/a&gt; (&lt;a href=&quot;https://github.com/jakob-stoeck/speechToText-android&quot;&gt;GitHub&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Source Code on GitHub: &lt;a href=&quot;https://github.com/jakobstoeck/&quot;&gt;https://github.com/jakobstoeck/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;

&lt;p&gt;You need to send the voice message you have to an iOS action. Depending on the app this opens behind a button called “Share”, “Forward” or “Export”.&lt;/p&gt;

&lt;svg style=&quot;float: left; margin-right: 5px&quot; version=&quot;1.0&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;12.000000pt&quot; height=&quot;17.000000pt&quot; viewBox=&quot;0 0 120.000000 173.000000&quot; preserveAspectRatio=&quot;xMidYMid meet&quot;&gt;
&lt;g transform=&quot;translate(0.000000,173.000000) scale(0.100000,-0.100000)&quot; fill=&quot;#000000&quot; stroke=&quot;none&quot;&gt;
&lt;path d=&quot;M468 1593 c-76 -76 -138 -143 -138 -148 0 -6 12 -19 27 -29 l26 -19
90 91 c49 51 91 92 93 92 2 0 4 -202 4 -450 l0 -450 35 0 35 0 0 452 0 453 93
-92 92 -92 27 22 26 22 -136 143 -137 143 -137 -138z&quot; /&gt;
&lt;path d=&quot;M0 640 l0 -600 600 0 600 0 0 600 0 600 -220 0 -220 0 0 -40 0 -40
180 0 180 0 0 -520 0 -520 -520 0 -520 0 0 520 0 520 180 0 180 0 0 40 0 40
-220 0 -220 0 0 -600z&quot; /&gt;
&lt;/g&gt;
&lt;/svg&gt;

&lt;p&gt;Often it’s also this share symbol.&lt;/p&gt;

&lt;p&gt;If you tap on it, the iOS actions open where you can choose That’s What She Said:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ios-action.png&quot; width=&quot;311&quot; alt=&quot;iOS action&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The transcribed text is shown after a few seconds as a notification:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ios-twss-text.png&quot; width=&quot;311&quot; alt=&quot;iOS action&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;supported-apps&quot;&gt;Supported Apps&lt;/h2&gt;

&lt;p&gt;Most apps should word since it only needs to support iOS actions. Those appear usually if you tap on “Share”, “Forward” or “Export”. I tried it succesfully with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;WhatsApp&lt;/li&gt;
  &lt;li&gt;Telegram&lt;/li&gt;
  &lt;li&gt;Voice Memos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One notable exception is the Apple Messages app. I couldn’t find any way to share or export a voice message in this app.&lt;/p&gt;

&lt;h2 id=&quot;privacy&quot;&gt;Privacy&lt;/h2&gt;

&lt;p&gt;Depending on the audio format voice is either sent directly to Google’s (for Opus and Flac) Speech Recognition service or Apple’s (all other audio formats). No other data is transmitted or stored.&lt;/p&gt;</content><author><name>It’s me!</name></author><summary type="html">Playing a bit with Java and Swift, I built two small apps for iOS and Android and solved a problem of mine: With “That’s What She Said” you receive the text of any voice message without listening to it.</summary></entry><entry><title type="html">RAM disk for faster applications under macOS</title><link href="https://www.jakobstoeck.de/2017/ramdisk-for-faster-applications-under-macos/" rel="alternate" type="text/html" title="RAM disk for faster applications under macOS" /><published>2017-06-13T15:13:00+00:00</published><updated>2017-06-13T15:13:00+00:00</updated><id>https://www.jakobstoeck.de/2017/ramdisk-for-faster-applications-under-macos</id><content type="html" xml:base="https://www.jakobstoeck.de/2017/ramdisk-for-faster-applications-under-macos/">&lt;p&gt;Theory:
A RAM disk might speed up IO-bound computations under macOS.&lt;/p&gt;

&lt;p&gt;Experiment:
Find maximum speedup&lt;/p&gt;

&lt;p&gt;Theoretical maximum. I use &lt;code class=&quot;highlighter-rouge&quot;&gt;pv&lt;/code&gt; (&lt;code class=&quot;highlighter-rouge&quot;&gt;$ brew install pv&lt;/code&gt;) to measure the throughput of writing data and then use the following options to get the average data througput for 450 MBs written: &lt;code class=&quot;highlighter-rouge&quot;&gt;pv --average-rate --stop-at-size --size450m&lt;/code&gt; or in short &lt;code class=&quot;highlighter-rouge&quot;&gt;pv -aSs450m&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;contrast-data-throughput-to-the-following-sinks&quot;&gt;Contrast data throughput to the following sinks:&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;the void&lt;/li&gt;
  &lt;li&gt;SSD&lt;/li&gt;
  &lt;li&gt;RAM disk&lt;/li&gt;
  &lt;li&gt;RAM disk mounted with OS mount command&lt;/li&gt;
  &lt;li&gt;RAM disk folders mounted with bindfs&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;the-void&quot;&gt;the void&lt;/h3&gt;

&lt;p&gt;This should be the fastest possible data rate: Piping zeroes into the void. For bigger files than 450 MB the troughput would be even higher, maxing out at around 17GiB/s.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pv &lt;span class=&quot;nt&quot;&gt;-aSs450m&lt;/span&gt; &amp;lt; /dev/zero &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;13.5GiB/s]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ssd&quot;&gt;SSD&lt;/h3&gt;

&lt;p&gt;My MacBook Pro Late 2012 SSD has a little over 300MiB/s write throughput in this test.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..10&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;pv &lt;span class=&quot;nt&quot;&gt;-aSs450m&lt;/span&gt; &amp;lt; /dev/zero &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 307MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 300MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 305MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 305MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 303MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 299MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 309MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 303MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 306MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 304MiB/s]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ram-disk&quot;&gt;RAM disk&lt;/h3&gt;

&lt;p&gt;First setup the ram disk:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ VOLUME_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;RamDisk
&lt;span class=&quot;nv&quot;&gt;$ SIZE_IN_MB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1024
&lt;span class=&quot;nv&quot;&gt;$ DEVICE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;hdiutil attach &lt;span class=&quot;nt&quot;&gt;-nobrowse&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-nomount&lt;/span&gt; ram://&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SIZE_IN_MB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;diskutil erasevolume HFS+ &lt;span class=&quot;nv&quot;&gt;$VOLUME_NAME&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DEVICE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The DDR3 RAM with 1600MHz in this setup has a throughput of ~1.38GiB/s. Nearly 5 times the SSD.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /Volumes/RamDisk
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..10&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;pv &lt;span class=&quot;nt&quot;&gt;-aSs450m&lt;/span&gt; &amp;lt; /dev/zero &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 1.3GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.29GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.37GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 1.4GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.35GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.36GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.39GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.39GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.38GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.37GiB/s]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ram-disk-mounted-with-os-mount-command&quot;&gt;RAM disk mounted with OS mount command&lt;/h3&gt;

&lt;p&gt;Applications write their cache inside files and folders. One way to move those folders to the RAM disk would be to replace them with symbolic links to the new destination on the RAM disk. This has the big disadvantage that the folders would stop working when the RAM disk is down (e.g. during/after a restart or when ejecting the ram disk).&lt;/p&gt;

&lt;p&gt;A more robust solution is to bind the folder to a folder on the RAM disk. Under linux the &lt;code class=&quot;highlighter-rouge&quot;&gt;mount --bind&lt;/code&gt; command can do this, under macOS this is not possible with single folders but only with whole devices: You can bind a folder to a device, i.e. the ram disk, but not to another folder on the ram disk.&lt;/p&gt;

&lt;p&gt;A trick is to create the base folder structure of the future ram disk in a folder on the harddisk and mount the ram disk over this folder. This way, even when the mount point is down, folder access gracefully falls back to the hard disk folder structure. Which is very important for some folders like &lt;code class=&quot;highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; which are needed during startup.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$DEVICE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/disk3 &lt;span class=&quot;c&quot;&gt;# return of hdiutil&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$MOUNT_POINT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/mounts&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$DIRECTORIES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/private/tmp'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;f &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DIRECTORIES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
	&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$f&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$MOUNT_POINT$f&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-vs&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$MOUNT_POINT$f&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$f&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done

&lt;/span&gt;newfs_hfs &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$MOUNT_POINT&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DEVICE&lt;/span&gt;
mount &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; noatime &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; hfs &lt;span class=&quot;nv&quot;&gt;$DEVICE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$MOUNT_POINT&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;f &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$DIRECTORIES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
	&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-vp&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$MOUNT_POINT$f&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$mount_point&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..10&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;pv &lt;span class=&quot;nt&quot;&gt;-aSs450m&lt;/span&gt; &amp;lt; /dev/zero &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.29GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.43GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.43GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.43GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.34GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.37GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.47GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.46GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.42GiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1.36GiB/s]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ram-disk-folders-mounted-with-bindfs&quot;&gt;RAM disk folders mounted with bindfs&lt;/h3&gt;

&lt;p&gt;In the last chapter we looked at how Linux can &lt;code class=&quot;highlighter-rouge&quot;&gt;mount --bind&lt;/code&gt; single folders. Under macOS we need to install &lt;code class=&quot;highlighter-rouge&quot;&gt;bindfs&lt;/code&gt; to be able to emulate it:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew cask &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;osxfuse &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;bindfs
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; ~/testdir
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bindfs /Volumes/RamDisk/testdir ~/testdir
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With our usual test we see that, unfortunately bindfs is much slower than even using the hard disk:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/testdir
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..10&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;pv &lt;span class=&quot;nt&quot;&gt;-aSs450m&lt;/span&gt; &amp;lt; /dev/zero &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 143MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 149MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 148MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 147MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 145MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 138MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 145MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 147MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 146MiB/s]
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; 146MiB/s]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To unmount the bindfs volumes it’s easiest to go to &lt;code class=&quot;highlighter-rouge&quot;&gt;$ open /Volumes/&lt;/code&gt; and click on the eject symbol.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Binding folders to a RAM disk significantly speeds up the write throughput of the bound folders. You may use it for hot paths in your file system where many files are constantly read and written.&lt;/p&gt;

&lt;h3 id=&quot;which-folders-may-be-sped-up&quot;&gt;Which folders may be sped up?&lt;/h3&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;fs_usage &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; 5 &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; filesys | &lt;span class=&quot;nb&quot;&gt;tee &lt;/span&gt;fs_usage.log | egrep &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'(/.+?) {3}'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'s/\/dev\/disk[^ ]+  //'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;uniq&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-nr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>It’s me!</name></author><summary type="html">Theory: A RAM disk might speed up IO-bound computations under macOS.</summary></entry><entry><title type="html">Websites which work great without JavaScript</title><link href="https://www.jakobstoeck.de/2017/websites-which-work-great-without-javascript/" rel="alternate" type="text/html" title="Websites which work great without JavaScript" /><published>2017-06-01T11:35:00+00:00</published><updated>2017-06-01T11:35:00+00:00</updated><id>https://www.jakobstoeck.de/2017/websites-which-work-great-without-javascript</id><content type="html" xml:base="https://www.jakobstoeck.de/2017/websites-which-work-great-without-javascript/">&lt;p&gt;Contrary to popular belief, the web still works quite well without JavaScript:&lt;/p&gt;

&lt;h2 id=&quot;these-sites-work-great-with-all-essential-functionality&quot;&gt;These sites work great with all essential functionality&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/&quot;&gt;Amazon.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Baidu.com/&quot;&gt;Baidu.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Blogger.com/&quot;&gt;Blogger.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://DuckDuckGo.com/&quot;&gt;DuckDuckGo.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://eBay.com/&quot;&gt;eBay.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Facebook.com/&quot;&gt;Facebook.com&lt;/a&gt; (redirects to mobile version)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Google.com/&quot;&gt;Google.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Medium.com/&quot;&gt;Medium.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Mozilla.org/&quot;&gt;Mozilla.org&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/&quot;&gt;news.ycombinator.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Reddit.com/&quot;&gt;Reddit.com&lt;/a&gt; (Desktop version)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://StackOverflow.com/&quot;&gt;StackOverflow.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Twitter.com/&quot;&gt;Twitter.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Wikipedia.org/&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://WordPress.com/&quot;&gt;WordPress.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Xkcd.com/&quot;&gt;Xkcd.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Yahoo.com/&quot;&gt;Yahoo.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;these-work-with-some-functionality-missing&quot;&gt;These work with some functionality missing&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://bing.com/&quot;&gt;bing.com&lt;/a&gt; (no images, no login)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://espn.com/&quot;&gt;espn.com&lt;/a&gt; (some images missing)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://GitHub.com/&quot;&gt;GitHub.com&lt;/a&gt; (read-only browsing works, opening PRs and the like not)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://GitLab.com/&quot;&gt;GitLab.com&lt;/a&gt; (read-only browsing works, drop down menus are not)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://meetup.com/&quot;&gt;meetup.com&lt;/a&gt; (no RSVP)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tumblr.com/&quot;&gt;tumblr.com&lt;/a&gt; (blogs work, the search does not)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://WashingtonPost.com/&quot;&gt;WashingtonPost.com&lt;/a&gt; (some images missing)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;do-not-work&quot;&gt;Do not work&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;any video except gifs (YouTube.com, Twitch.tv, even native HTML5 videos need JavaScript for the play event. There are applications which support YouTube URLs though, like VLC: &lt;code class=&quot;highlighter-rouge&quot;&gt;vlc 'https:// www.youtube.com/watch?v=somevideoid'&lt;/code&gt;, though)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://instagram.com/&quot;&gt;instagram.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://linkedin.com/&quot;&gt;linkedin.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://maps.google.com/&quot;&gt;maps.google.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Netflix.com/&quot;&gt;Netflix.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://Reddit.com/&quot;&gt;Reddit.com&lt;/a&gt; (mobile version. alternative: use the desktop version)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://taobao.com/&quot;&gt;taobao.com&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ted.com/&quot;&gt;ted.com&lt;/a&gt; (video is not playing, download button does not work either, but that could be fixed easily)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://translate.google.com/&quot;&gt;translate.google.com&lt;/a&gt; (error 403)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;why-disable-javascript&quot;&gt;Why disable JavaScript?&lt;/h1&gt;

&lt;h2 id=&quot;faster-browsing&quot;&gt;Faster browsing&lt;/h2&gt;

&lt;p&gt;Loading times are much lower since JavaScript files are not requested. Rendering times are also faster because no scripts are executed during this phase. Most pages are finished in under one second.&lt;/p&gt;

&lt;h2 id=&quot;less-cpu-usage&quot;&gt;Less CPU usage&lt;/h2&gt;

&lt;p&gt;Besides the initial loading, many sites are continuously executing scripts which put load on the CPU. Badly written pages even more so.&lt;/p&gt;

&lt;h2 id=&quot;more-battery-on-mobile&quot;&gt;More battery on mobile&lt;/h2&gt;

&lt;p&gt;Mobile surfing holds up much longer.&lt;/p&gt;

&lt;h2 id=&quot;less-intrusive-animations&quot;&gt;Less intrusive animations&lt;/h2&gt;

&lt;p&gt;No “subscribe to our newsletter” popups, no scrolling-based “this might interest you” notifications. No changing of scrolling behavior.&lt;/p&gt;

&lt;h1 id=&quot;how-to-disable-javascript&quot;&gt;How to disable JavaScript&lt;/h1&gt;

&lt;p&gt;Go cold turkey:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Safari: Develop &amp;gt; Disable JavaScript&lt;/li&gt;
  &lt;li&gt;iOS: Settings &amp;gt; Safari &amp;gt; Advanced &amp;gt; JavaScript&lt;/li&gt;
  &lt;li&gt;Chrome: Preferences &amp;gt; Show Advanced Settings … &amp;gt; Content Settings … &amp;gt; Do not allow any sites to run JavaScript&lt;/li&gt;
  &lt;li&gt;Firefox: about:config &amp;gt; javascript.enabled = false&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pro Tips:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For Safari under macOS you can set a Keyboard Shortcut to toggle JavaScript under System Preferences, e.g. Cmd-Shift-J&lt;/li&gt;
  &lt;li&gt;For Chrome you can add exceptions to sites you like to always run JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternatively use an extension like NoScript.&lt;/p&gt;

&lt;p&gt;If you want to add a site or change something &lt;a href=&quot;https://github.com/jakob-stoeck/jakobstoeck.de/edit/master/_posts/2017-06-01-websites-which-work-great-without-javascript.md&quot;&gt;just edit this page.&lt;/a&gt; &lt;em&gt;With&lt;/em&gt; JavaScript since GitHubs commit button does not work without it. If anyone from GitHub is reading this, it would be great if you could fix this 😉&lt;/p&gt;</content><author><name>It’s me!</name></author><summary type="html">Contrary to popular belief, the web still works quite well without JavaScript:</summary></entry><entry><title type="html">How to encrypt RTMP (or anything really) over SSL/TLS</title><link href="https://www.jakobstoeck.de/2017/how-to-encrypt-rtmp-or-anything-really-over-ssl-tls/" rel="alternate" type="text/html" title="How to encrypt RTMP (or anything really) over SSL/TLS" /><published>2017-05-16T13:36:15+00:00</published><updated>2017-05-16T13:36:15+00:00</updated><id>https://www.jakobstoeck.de/2017/how-to-encrypt-rtmp-or-anything-really-over-ssl-tls</id><content type="html" xml:base="https://www.jakobstoeck.de/2017/how-to-encrypt-rtmp-or-anything-really-over-ssl-tls/">&lt;p&gt;You want to communicate over a secure channel but your client application doesn’t support it? That’s a job for a transparent SSL proxy.&lt;/p&gt;

&lt;p&gt;This articles describes on how to use stunnel as a transparent proxy to encrypt communication. With a transparent proxy you do not need to change the client application.&lt;/p&gt;

&lt;h1 id=&quot;problem&quot;&gt;Problem&lt;/h1&gt;

&lt;p&gt;You want to send data securely between two computers over the internet but your sender application does not support SSL.&lt;/p&gt;

&lt;h1 id=&quot;example&quot;&gt;Example&lt;/h1&gt;

&lt;p&gt;You want to stream a video with &lt;a href=&quot;https://ffmpeg.org&quot;&gt;ffmpeg&lt;/a&gt; over RTMP to an RTMP server like &lt;a href=&quot;https://www.wowza.com&quot;&gt;Wowza&lt;/a&gt; or &lt;a href=&quot;https://github.com/arut/nginx-rtmp-module&quot;&gt;nginx with an rtmp module&lt;/a&gt;. While ffmpeg supports RTMP it does not support the SSL-encrypted version RTMPS.&lt;/p&gt;

&lt;p&gt;We use &lt;a href=&quot;https://www.stunnel.org/&quot;&gt;stunnel&lt;/a&gt; to wrap the RTMP stream with SSL/TLS (“SSL proxy”) and deliver it to the RTMP server. The server uses stunnel again to decrypt the RTMP stream.&lt;/p&gt;

&lt;svg width=&quot;440px&quot; height=&quot;81px&quot; style=&quot;background-color:rgb(255, 255, 255)&quot; version=&quot;1.1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;
 &lt;g transform=&quot;translate(.5 .5)&quot;&gt;
  &lt;path d=&quot;m100 0h40l20 40-20 40h-40l-20-40z&quot; fill=&quot;#f5f5f5&quot; pointer-events=&quot;none&quot; stroke=&quot;#666&quot; stroke-dasharray=&quot;3 3&quot; stroke-miterlimit=&quot;10&quot; /&gt;
  &lt;g transform=&quot;translate(105.5,26.5)&quot;&gt;
   &lt;switch&gt;
    &lt;foreignObject width=&quot;29&quot; height=&quot;26&quot; overflow=&quot;visible&quot; pointer-events=&quot;all&quot; requiredFeatures=&quot;http://www.w3.org/TR/SVG11/feature#Extensibility&quot;&gt;
     &lt;div color=&quot;rgb(0, 0, 0)&quot; display=&quot;inline-block&quot; font-family=&quot;Helvetica&quot; font-size=&quot;12px&quot; text-align=&quot;center&quot; style=&quot;line-height:1.2;vertical-align:top;white-space:nowrap;width:30px;word-wrap:normal&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
      &lt;div display=&quot;inline-block&quot; text-align=&quot;inherit&quot; text-decoration=&quot;inherit&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;SSL
       &lt;div&gt;proxy&lt;/div&gt;
      &lt;/div&gt;
     &lt;/div&gt;
    &lt;/foreignObject&gt;
    &lt;text x=&quot;15&quot; y=&quot;19&quot; fill=&quot;#000000&quot; font-family=&quot;Helvetica&quot; font-size=&quot;12px&quot; text-anchor=&quot;middle&quot;&gt;[Not supported by viewer]&lt;/text&gt;
   &lt;/switch&gt;
  &lt;/g&gt;
  &lt;g transform=&quot;translate(11.5,19.5)&quot;&gt;
   &lt;switch&gt;
    &lt;foreignObject width=&quot;37&quot; height=&quot;40&quot; overflow=&quot;visible&quot; pointer-events=&quot;all&quot; requiredFeatures=&quot;http://www.w3.org/TR/SVG11/feature#Extensibility&quot;&gt;
     &lt;div color=&quot;rgb(0, 0, 0)&quot; display=&quot;inline-block&quot; font-family=&quot;Helvetica&quot; font-size=&quot;12px&quot; text-align=&quot;center&quot; style=&quot;line-height:1.2;vertical-align:top;white-space:nowrap;width:38px;word-wrap:normal&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
      &lt;div display=&quot;inline-block&quot; text-align=&quot;inherit&quot; text-decoration=&quot;inherit&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;sender
       &lt;div&gt;e.g.&lt;/div&gt;
       &lt;div&gt;ffmpeg&lt;/div&gt;
      &lt;/div&gt;
     &lt;/div&gt;
    &lt;/foreignObject&gt;
    &lt;text x=&quot;19&quot; y=&quot;26&quot; fill=&quot;#000000&quot; font-family=&quot;Helvetica&quot; font-size=&quot;12px&quot; text-anchor=&quot;middle&quot;&gt;[Not supported by viewer]&lt;/text&gt;
   &lt;/switch&gt;
  &lt;/g&gt;
  &lt;g transform=&quot;translate(344.5,19.5)&quot;&gt;
   &lt;switch&gt;
    &lt;foreignObject width=&quot;70&quot; height=&quot;40&quot; overflow=&quot;visible&quot; pointer-events=&quot;all&quot; requiredFeatures=&quot;http://www.w3.org/TR/SVG11/feature#Extensibility&quot;&gt;
     &lt;div color=&quot;rgb(0, 0, 0)&quot; display=&quot;inline-block&quot; font-family=&quot;Helvetica&quot; font-size=&quot;12px&quot; text-align=&quot;center&quot; style=&quot;line-height:1.2;vertical-align:top;white-space:nowrap;width:71px;word-wrap:normal&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
      &lt;div display=&quot;inline-block&quot; text-align=&quot;inherit&quot; text-decoration=&quot;inherit&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;receiver
       &lt;div&gt;e.g.&lt;/div&gt;
       &lt;div&gt;RTMP server&lt;/div&gt;
      &lt;/div&gt;
     &lt;/div&gt;
    &lt;/foreignObject&gt;
    &lt;text x=&quot;35&quot; y=&quot;26&quot; fill=&quot;#000000&quot; font-family=&quot;Helvetica&quot; font-size=&quot;12px&quot; text-anchor=&quot;middle&quot;&gt;[Not supported by viewer]&lt;/text&gt;
   &lt;/switch&gt;
  &lt;/g&gt;
  &lt;path d=&quot;m306.37 40h27.26&quot; fill=&quot;none&quot; pointer-events=&quot;none&quot; stroke=&quot;#000&quot; stroke-miterlimit=&quot;10&quot; /&gt;
  &lt;path d=&quot;m301.12 40l7-3.5-1.75 3.5 1.75 3.5z&quot; pointer-events=&quot;none&quot; stroke=&quot;#000&quot; stroke-miterlimit=&quot;10&quot; /&gt;
  &lt;path d=&quot;m338.88 40l-7 3.5 1.75-3.5-1.75-3.5z&quot; pointer-events=&quot;none&quot; stroke=&quot;#000&quot; stroke-miterlimit=&quot;10&quot; /&gt;
  &lt;path d=&quot;m210 20c-24 0-30 20-10.8 24-19.2 8.8 2.4 28 18 20 10.8 16 46.8 16 58.8 0 24 0 24-16 9-24 15-16-9-32-30-24-15-12-39-12-45 4z&quot; fill=&quot;#fff&quot; pointer-events=&quot;none&quot; stroke=&quot;#000&quot; stroke-miterlimit=&quot;10&quot; /&gt;
  &lt;g transform=&quot;translate(219.5,33.5)&quot;&gt;
   &lt;switch&gt;
    &lt;foreignObject width=&quot;41&quot; height=&quot;12&quot; overflow=&quot;visible&quot; pointer-events=&quot;all&quot; requiredFeatures=&quot;http://www.w3.org/TR/SVG11/feature#Extensibility&quot;&gt;
     &lt;div color=&quot;rgb(0, 0, 0)&quot; display=&quot;inline-block&quot; font-family=&quot;Helvetica&quot; font-size=&quot;12px&quot; text-align=&quot;center&quot; style=&quot;line-height:1.2;vertical-align:top;white-space:nowrap;width:42px;word-wrap:normal&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
      &lt;div display=&quot;inline-block&quot; text-align=&quot;inherit&quot; text-decoration=&quot;inherit&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;Internet&lt;/div&gt;
     &lt;/div&gt;
    &lt;/foreignObject&gt;
    &lt;text x=&quot;21&quot; y=&quot;12&quot; fill=&quot;#000000&quot; font-family=&quot;Helvetica&quot; font-size=&quot;12px&quot; text-anchor=&quot;middle&quot;&gt;Internet&lt;/text&gt;
   &lt;/switch&gt;
  &lt;/g&gt;
  &lt;path d=&quot;m66.37 40h107.26&quot; fill=&quot;none&quot; pointer-events=&quot;none&quot; stroke=&quot;#000&quot; stroke-miterlimit=&quot;10&quot; /&gt;
  &lt;path d=&quot;m61.12 40l7-3.5-1.75 3.5 1.75 3.5z&quot; pointer-events=&quot;none&quot; stroke=&quot;#000&quot; stroke-miterlimit=&quot;10&quot; /&gt;
  &lt;path d=&quot;m178.88 40l-7 3.5 1.75-3.5-1.75-3.5z&quot; pointer-events=&quot;none&quot; stroke=&quot;#000&quot; stroke-miterlimit=&quot;10&quot; /&gt;
 &lt;/g&gt;
&lt;/svg&gt;

&lt;p&gt;Now the sender acts as if it supports encryption and decryption. In the case of ffmpeg it would send an encrypted stream when the SSL proxy is active and an unencrypted one when the SSL proxy is inactive:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ffmpeg &lt;span class=&quot;nt&quot;&gt;-re&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;~/some.mp3&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-acodec&lt;/span&gt; copy &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; flv &lt;span class=&quot;s1&quot;&gt;'rtmp://www.example.org:443'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;solution&quot;&gt;Solution&lt;/h1&gt;

&lt;p&gt;The needed steps are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install stunnel on a server called gateway&lt;/li&gt;
  &lt;li&gt;Route the sender traffic to the gateway without changing the receiver destination&lt;/li&gt;
  &lt;li&gt;Configure stunnel to re-route the traffic to the receiver address after SSL-wrapping it&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;1-install-stunnel-on-a-server&quot;&gt;1. Install stunnel on a server&lt;/h2&gt;

&lt;p&gt;Stunnel runs on all popular operating systems. To install it use your package manager, e.g. on macOS &lt;code class=&quot;highlighter-rouge&quot;&gt;brew install stunnel&lt;/code&gt;. Stunnel accepts an incoming connection on a specified port, encrypts it and send it to another specified address.&lt;/p&gt;

&lt;p&gt;The default configuration location is &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/stunnel/stunnel.conf&lt;/code&gt; (or &lt;code class=&quot;highlighter-rouge&quot;&gt;$(brew --prefix)/etc/stunnel/stunnel.conf&lt;/code&gt; on macOS). Change its content to&lt;/p&gt;

&lt;div class=&quot;language-config highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# /etc/stunnel/stunnel.conf
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foreground&lt;/span&gt; = &lt;span class=&quot;n&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt; = &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;

[&lt;span class=&quot;n&quot;&gt;my&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;encryption&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;]
&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; = &lt;span class=&quot;n&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;accept&lt;/span&gt; = &lt;span class=&quot;m&quot;&gt;1234&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt; = &lt;span class=&quot;n&quot;&gt;www&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;:&lt;span class=&quot;m&quot;&gt;443&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Stunnel now listens to traffic on port 1234, encrypts this traffic and routes it to www.example.org on port 443. For further explanation of the config parameters check &lt;code class=&quot;highlighter-rouge&quot;&gt;$ man stunnel&lt;/code&gt;. You can test the configuration by starting stunnel and on the same machine connecting to port 1234 (in another terminal window since stunnel is set to &lt;code class=&quot;highlighter-rouge&quot;&gt;foreground = yes&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo stunnel
$ echo &quot;hi&quot; | nc 127.0.0.1 1234
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The stunnel log should then show that you successfully connected to the remote server over a secure connection:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[…]
LOG5[0]: Service [my-encryption-service] accepted connection from 127.0.0.1:53870
LOG5[0]: s_connect: connected 93.184.216.34:443
LOG5[0]: Service [my-encryption-service] connected remote server from 192.168.0.1:53871
LOG5[0]: Connection closed: 3 byte(s) sent to TLS, 0 byte(s) sent to socket
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You could stop here if the destination addresses were known beforehand and could be written in the config. In our example that’s not the case so proceed to step 2:&lt;/p&gt;

&lt;h2 id=&quot;2-route-the-sender-traffic-to-the-gateway-without-changing-the-receiver-destination&quot;&gt;2. Route the sender traffic to the gateway without changing the receiver destination&lt;/h2&gt;

&lt;p&gt;Now that stunnel works, all the to-be-encrypted traffic needs to be directed to the stunnel port transparently, i.e. without the sender knowing that its traffic gets redirected. This can be done by setting the stunnel server IP as a gateway for the client.&lt;/p&gt;

&lt;p&gt;On the sender: Setting a gateway or router IP is usually done in the network configuration. Depending on the client application or operating system that is done in different ways. Search for “set default gateway” and add the operating system your sender runs on if you’re not sure. Then set the “gateway” or “router” IP to the stunnel server from step 1. Now all the traffic which is sent from the client is routed to the gateway address.&lt;/p&gt;

&lt;p&gt;On the gateway: The gateway needs to be configured to not drop those packets but to route them to their destination. This is called “IP Forwarding” and should be enabled. Under Linux that can be done with &lt;code class=&quot;highlighter-rouge&quot;&gt;$ echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward&lt;/code&gt;. Search online for other operating systems.&lt;/p&gt;

&lt;p&gt;Now the client computer should still be able to normally access the network but all its traffic is routed over the gateway before accessing the internet. Which enables us to do the last step:&lt;/p&gt;

&lt;h2 id=&quot;3-configure-stunnel-to-re-route-the-traffic-to-its-original-destination-after-ssl-wrapping-it&quot;&gt;3. Configure stunnel to re-route the traffic to its original destination after SSL-wrapping it&lt;/h2&gt;

&lt;p&gt;Instead of hard-coding a destination like we did in step 1, change the stunnel configuration to read like this:&lt;/p&gt;

&lt;div class=&quot;language-config highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# /etc/stunnel/stunnel.conf
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foreground&lt;/span&gt; = &lt;span class=&quot;n&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt; = &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;

[&lt;span class=&quot;n&quot;&gt;my&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;encryption&lt;/span&gt;-&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;]
&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; = &lt;span class=&quot;n&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;accept&lt;/span&gt; = &lt;span class=&quot;m&quot;&gt;443&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;transparent&lt;/span&gt; = &lt;span class=&quot;n&quot;&gt;destination&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;accept&lt;/code&gt; port should be equal to the port on the receiver side and we do not have a hard-coded destination anymore but instead use the original destination.&lt;/p&gt;

&lt;p&gt;On the gateway: Route the incoming traffic which is directed to port 443 to the local port 443 of stunnel. To do this you need to know how your network is named (look at &lt;code class=&quot;highlighter-rouge&quot;&gt;$ ifconfig&lt;/code&gt;, in this example I use “eth0” and a Linux gateway):&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 443 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;iptables &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; nat &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; PREROUTING &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 443 &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; eth0 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; DNAT &lt;span class=&quot;nt&quot;&gt;--to-destination&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;youriphere]:443
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;make-it-secure&quot;&gt;Make it secure&lt;/h3&gt;

&lt;p&gt;Now you should be able to connect to any service with your sender over an encrypted connection as long as you use the configured port (443 in our example) in the destination address.&lt;/p&gt;

&lt;p&gt;To prevent man in the middle attacks, tell stunnel which certificates to accept by concatenating all the valid certificates in a file and add this to the config:&lt;/p&gt;

&lt;div class=&quot;language-config highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# /etc/stunnel/stunnel.conf
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;verify&lt;/span&gt; = &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CAfile&lt;/span&gt; = /&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;stunnel&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;your_certificates&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;crt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ask the receiver maintainer which certificates are valid or have a look yourself at the current certificate chain with this command:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;openssl s_client &lt;span class=&quot;nt&quot;&gt;-showcerts&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; www.example.org:443 &amp;lt;/dev/null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;limitations&quot;&gt;Limitations&lt;/h1&gt;

&lt;p&gt;If you need &lt;a href=&quot;https://en.wikipedia.org/wiki/Server_Name_Indication&quot;&gt;SNI&lt;/a&gt; this approach might not work with all protocols without additional work. The reason is that for SNI you need the destination domain which is written inside the application protocol and must be read by stunnel. But stunnel does not understand all protocols (it normally doesn’t need to for just encrypting it). It does understand some protocols, though, like imap, http, proxy, smtp and others.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.stunnel.org/perf.html&quot;&gt;performance of stunnel&lt;/a&gt; is nice, but you need to pay attention to some settings like ulimit and which ciphers you use.&lt;/p&gt;</content><author><name>It’s me!</name></author><summary type="html">You want to communicate over a secure channel but your client application doesn’t support it? That’s a job for a transparent SSL proxy.</summary></entry><entry><title type="html">Updates for macOS</title><link href="https://www.jakobstoeck.de/2017/updates-for-macos/" rel="alternate" type="text/html" title="Updates for macOS" /><published>2017-04-25T12:00:01+00:00</published><updated>2017-04-25T12:00:01+00:00</updated><id>https://www.jakobstoeck.de/2017/updates-for-macos</id><content type="html" xml:base="https://www.jakobstoeck.de/2017/updates-for-macos/">&lt;p&gt;Installing and updating system packages and applications is much easier under macOS using the CLI if you use &lt;a href=&quot;https://brew.sh&quot;&gt;homebrew&lt;/a&gt; and the &lt;a href=&quot;https://github.com/mas-cli/mas&quot;&gt;Mac App Store Command Line Interface&lt;/a&gt;, then you can just:&lt;/p&gt;

&lt;p&gt;update all the system components,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;softwareupdate &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;update all the apps installed via the App Store and&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mas upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;update everything installed via brew and cleans up the otherwise always growing cache folder&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew upgrade &lt;span class=&quot;nt&quot;&gt;--cleanup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you have a completely up-to-date machine. I added this with some additional upgrade commands to my .zshrc to have a shell function for it, so I can just type &lt;code class=&quot;highlighter-rouge&quot;&gt;$ upgrade&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;upgrade&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# updates system updates, mac app store, homebrew packages and ruby gems&lt;/span&gt;
	softwareupdate &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt;
	mas upgrade
	brew upgrade
	brew cleanup &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;app &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;brew cask outdated &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;brew cask &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--force&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done
	&lt;/span&gt;brew cask cleanup
	gem update &lt;span class=&quot;nt&quot;&gt;--no-document&lt;/span&gt;
	gem cleanup
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
outdated&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	softwareupdate &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
	mas outdated
	brew outdated
	brew cask outdated
	gem outdated
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>It’s me!</name></author><summary type="html">Updates everything on your Mac with one CLI command</summary></entry></feed>