A place to cache linked articles (think custom and personal wayback machine)
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

index.html 51KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang=fr>
  4. <!-- Has to be within the first 1024 bytes, hence before the <title>
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset=utf-8>
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name=viewport content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>HOMEBREWSERVER.CLUB (archive) — David Larlet</title>
  13. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  14. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
  15. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
  16. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
  17. <link rel="manifest" href="/manifest.json">
  18. <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
  19. <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
  20. <meta name="apple-mobile-web-app-title" content="David Larlet">
  21. <meta name="application-name" content="David Larlet">
  22. <meta name="msapplication-TileColor" content="#da532c">
  23. <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
  24. <meta name="theme-color" content="#f0f0ea">
  25. <!-- That good ol' feed, subscribe :p. -->
  26. <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
  27. <meta name="robots" content="noindex, nofollow">
  28. <meta content="origin-when-cross-origin" name="referrer">
  29. <!-- Canonical URL for SEO purposes -->
  30. <link rel="canonical" href="https://homebrewserver.club/low-tech-website-howto.html">
  31. <style>
  32. /* http://meyerweb.com/eric/tools/css/reset/ */
  33. html, body, div, span,
  34. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  35. a, abbr, address, big, cite, code,
  36. del, dfn, em, img, ins,
  37. small, strike, strong, tt, var,
  38. dl, dt, dd, ol, ul, li,
  39. fieldset, form, label, legend,
  40. table, caption, tbody, tfoot, thead, tr, th, td,
  41. article, aside, canvas, details, embed,
  42. figure, figcaption, footer, header, hgroup,
  43. menu, nav, output, ruby, section, summary,
  44. time, mark, audio, video {
  45. margin: 0;
  46. padding: 0;
  47. border: 0;
  48. font-size: 100%;
  49. font: inherit;
  50. vertical-align: baseline;
  51. }
  52. /* HTML5 display-role reset for older browsers */
  53. article, aside, details, figcaption, figure,
  54. footer, header, hgroup, menu, nav, section { display: block; }
  55. body { line-height: 1; }
  56. blockquote, q { quotes: none; }
  57. blockquote:before, blockquote:after,
  58. q:before, q:after {
  59. content: '';
  60. content: none;
  61. }
  62. table {
  63. border-collapse: collapse;
  64. border-spacing: 0;
  65. }
  66. /* http://practicaltypography.com/equity.html */
  67. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  68. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  69. @font-face {
  70. font-family: 'EquityTextB';
  71. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  72. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  73. font-weight: 300;
  74. font-style: normal;
  75. font-display: swap;
  76. }
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: italic;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  89. font-weight: 700;
  90. font-style: normal;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'ConcourseT3';
  95. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  96. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  97. font-weight: 300;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  102. body {
  103. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  104. font-family: "EquityTextB", Palatino, serif;
  105. background-color: #f0f0ea;
  106. color: #07486c;
  107. font-kerning: normal;
  108. -moz-osx-font-smoothing: grayscale;
  109. -webkit-font-smoothing: subpixel-antialiased;
  110. text-rendering: optimizeLegibility;
  111. font-variant-ligatures: common-ligatures contextual;
  112. font-feature-settings: "kern", "liga", "clig", "calt";
  113. }
  114. pre, code, kbd, samp, var, tt {
  115. font-family: 'TriplicateT4c', monospace;
  116. }
  117. em {
  118. font-style: italic;
  119. color: #323a45;
  120. }
  121. strong {
  122. font-weight: bold;
  123. color: black;
  124. }
  125. nav {
  126. background-color: #323a45;
  127. color: #f0f0ea;
  128. display: flex;
  129. justify-content: space-around;
  130. padding: 1rem .5rem;
  131. }
  132. nav:last-child {
  133. border-bottom: 1vh solid #2d7474;
  134. }
  135. nav a {
  136. color: #f0f0ea;
  137. }
  138. nav abbr {
  139. border-bottom: 1px dotted white;
  140. }
  141. h1 {
  142. border-top: 1vh solid #2d7474;
  143. border-bottom: .2vh dotted #2d7474;
  144. background-color: #e3e1e1;
  145. color: #323a45;
  146. text-align: center;
  147. padding: 5rem 0 4rem 0;
  148. width: 100%;
  149. font-family: 'ConcourseT3';
  150. display: flex;
  151. flex-direction: column;
  152. }
  153. h1.single {
  154. padding-bottom: 10rem;
  155. }
  156. h1 span {
  157. position: absolute;
  158. top: 1vh;
  159. left: 20%;
  160. line-height: 0;
  161. }
  162. h1 span a {
  163. line-height: 1.7;
  164. padding: 1rem 1.2rem .6rem 1.2rem;
  165. border-radius: 0 0 6% 6%;
  166. background: #2d7474;
  167. font-size: 1.3rem;
  168. color: white;
  169. text-decoration: none;
  170. }
  171. h2 {
  172. margin: 4rem 0 1rem;
  173. border-top: .2vh solid #2d7474;
  174. padding-top: 1vh;
  175. }
  176. h3 {
  177. text-align: center;
  178. margin: 3rem 0 .75em;
  179. }
  180. hr {
  181. height: .4rem;
  182. width: .4rem;
  183. border-radius: .4rem;
  184. background: #07486c;
  185. margin: 2.5rem auto;
  186. }
  187. time {
  188. display: bloc;
  189. margin-left: 0 !important;
  190. }
  191. ul, ol {
  192. margin: 2rem;
  193. }
  194. ul {
  195. list-style-type: square;
  196. }
  197. a {
  198. text-decoration-skip-ink: auto;
  199. text-decoration-thickness: 0.05em;
  200. text-underline-offset: 0.09em;
  201. }
  202. article {
  203. max-width: 50rem;
  204. display: flex;
  205. flex-direction: column;
  206. margin: 2rem auto;
  207. }
  208. article.single {
  209. border-top: .2vh dotted #2d7474;
  210. margin: -6rem auto 1rem auto;
  211. background: #f0f0ea;
  212. padding: 2rem;
  213. }
  214. article p:last-child {
  215. margin-bottom: 1rem;
  216. }
  217. p {
  218. padding: 0 .5rem;
  219. margin-left: 3rem;
  220. }
  221. p + p,
  222. figure + p {
  223. margin-top: 2rem;
  224. }
  225. blockquote {
  226. background-color: #e3e1e1;
  227. border-left: .5vw solid #2d7474;
  228. display: flex;
  229. flex-direction: column;
  230. align-items: center;
  231. padding: 1rem;
  232. margin: 1.5rem;
  233. }
  234. blockquote cite {
  235. font-style: italic;
  236. }
  237. blockquote p {
  238. margin-left: 0;
  239. }
  240. figure {
  241. border-top: .2vh solid #2d7474;
  242. background-color: #e3e1e1;
  243. text-align: center;
  244. padding: 1.5rem 0;
  245. margin: 1rem 0 0;
  246. font-size: 1.5rem;
  247. width: 100%;
  248. }
  249. figure img {
  250. max-width: 250px;
  251. max-height: 250px;
  252. border: .5vw solid #323a45;
  253. padding: 1px;
  254. }
  255. figcaption {
  256. padding: 1rem;
  257. line-height: 1.4;
  258. }
  259. aside {
  260. display: flex;
  261. flex-direction: column;
  262. background-color: #e3e1e1;
  263. padding: 1rem 0;
  264. border-bottom: .2vh solid #07486c;
  265. }
  266. aside p {
  267. max-width: 50rem;
  268. margin: 0 auto;
  269. }
  270. /* https://fvsch.com/code/css-locks/ */
  271. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  272. font-size: 1rem;
  273. line-height: calc( 1.5em + 0.2 * 1rem );
  274. }
  275. h1 {
  276. font-size: 1.9rem;
  277. line-height: calc( 1.2em + 0.2 * 1rem );
  278. }
  279. h2 {
  280. font-size: 1.6rem;
  281. line-height: calc( 1.3em + 0.2 * 1rem );
  282. }
  283. h3 {
  284. font-size: 1.35rem;
  285. line-height: calc( 1.4em + 0.2 * 1rem );
  286. }
  287. @media (min-width: 20em) {
  288. /* The (100vw - 20rem) / (50 - 20) part
  289. resolves to 0-1rem, depending on the
  290. viewport width (between 20em and 50em). */
  291. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  292. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  293. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  294. margin-left: 0;
  295. }
  296. h1 {
  297. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  298. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  299. }
  300. h2 {
  301. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  302. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  303. }
  304. h3 {
  305. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. }
  309. @media (min-width: 50em) {
  310. /* The right part of the addition *must* be a
  311. rem value. In this example we *could* change
  312. the whole declaration to font-size:2.5rem,
  313. but if our baseline value was not expressed
  314. in rem we would have to use calc. */
  315. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  316. font-size: calc( 1rem + .6 * 1rem );
  317. line-height: 1.5em;
  318. }
  319. p, li, pre, details {
  320. margin-left: 3rem;
  321. }
  322. h1 {
  323. font-size: calc( 1.9rem + 1.5 * 1rem );
  324. line-height: 1.2em;
  325. }
  326. h2 {
  327. font-size: calc( 1.5rem + 1.5 * 1rem );
  328. line-height: 1.3em;
  329. }
  330. h3 {
  331. font-size: calc( 1.35rem + 1.5 * 1rem );
  332. line-height: 1.4em;
  333. }
  334. figure img {
  335. max-width: 500px;
  336. max-height: 500px;
  337. }
  338. }
  339. figure.unsquared {
  340. margin-bottom: 1.5rem;
  341. }
  342. figure.unsquared img {
  343. height: inherit;
  344. }
  345. @media print {
  346. body { font-size: 100%; }
  347. a:after { content: " (" attr(href) ")"; }
  348. a, a:link, a:visited, a:after {
  349. text-decoration: underline;
  350. text-shadow: none !important;
  351. background-image: none !important;
  352. background: white;
  353. color: black;
  354. }
  355. abbr[title] { border-bottom: 0; }
  356. abbr[title]:after { content: " (" attr(title) ")"; }
  357. img { page-break-inside: avoid; }
  358. @page { margin: 2cm .5cm; }
  359. h1, h2, h3 { page-break-after: avoid; }
  360. p3 { orphans: 3; widows: 3; }
  361. img {
  362. max-width: 250px !important;
  363. max-height: 250px !important;
  364. }
  365. nav, aside { display: none; }
  366. }
  367. ul.with_columns {
  368. column-count: 1;
  369. }
  370. @media (min-width: 20em) {
  371. ul.with_columns {
  372. column-count: 2;
  373. }
  374. }
  375. @media (min-width: 50em) {
  376. ul.with_columns {
  377. column-count: 3;
  378. }
  379. }
  380. ul.with_two_columns {
  381. column-count: 1;
  382. }
  383. @media (min-width: 20em) {
  384. ul.with_two_columns {
  385. column-count: 1;
  386. }
  387. }
  388. @media (min-width: 50em) {
  389. ul.with_two_columns {
  390. column-count: 2;
  391. }
  392. }
  393. .gallery {
  394. display: flex;
  395. flex-wrap: wrap;
  396. justify-content: space-around;
  397. }
  398. .gallery figure img {
  399. margin-left: 1rem;
  400. margin-right: 1rem;
  401. }
  402. .gallery figure figcaption {
  403. font-family: 'ConcourseT3'
  404. }
  405. footer {
  406. font-family: 'ConcourseT3';
  407. display: flex;
  408. flex-direction: column;
  409. border-top: 3px solid white;
  410. padding: 4rem 0;
  411. background-color: #07486c;
  412. color: white;
  413. }
  414. footer > * {
  415. max-width: 50rem;
  416. margin: 0 auto;
  417. }
  418. footer a {
  419. color: #f1c40f;
  420. }
  421. footer .avatar {
  422. width: 200px;
  423. height: 200px;
  424. border-radius: 50%;
  425. float: left;
  426. -webkit-shape-outside: circle();
  427. shape-outside: circle();
  428. margin-right: 2rem;
  429. padding: 2px 5px 5px 2px;
  430. background: white;
  431. border-left: 1px solid #f1c40f;
  432. border-top: 1px solid #f1c40f;
  433. border-right: 5px solid #f1c40f;
  434. border-bottom: 5px solid #f1c40f;
  435. }
  436. </style>
  437. <h1>
  438. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  439. HOMEBREWSERVER.CLUB (archive)
  440. <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
  441. </h1>
  442. <section>
  443. <article>
  444. <h3><a href="https://homebrewserver.club/low-tech-website-howto.html">Source originale du contenu</a></h3>
  445. <p>Earlier this year we’ve been asked to help redesign the website of <a href="http://lowtechmagazine.com">lowtechmagazine.com</a>. The primary goal of the redesign was to radically reduce the energy use associated with accesing their web content. At the same time it is an attempt to find out what a low-tech website could be.</p>
  446. <p>In general the idea behind lowtechmagazine.com is to understand technologies and techniques of the past and combine them with the knowledge of today. Not in order to be able to ‘do more with the same’, but rather ‘to do the same with less’. </p>
  447. <p>In this particular case it means that all the optimizations and increases in efficiency do not go towards making a website which is faster at delivering even more megabytes. Rather it is a website which uses all the advances in technological efficiency, combined with specific hardware and software choices, to radically and drastically cut resource usage. At the same time for us a sustainable web site means ensuring support for older hardware, slower networks and improving the portability and archivability of the blog’s content.</p>
  448. <p>This meant making a website and server which could be hosted from the off-grid solar system used in the lowtechmagazine.com’s home-office in Barcelona. </p>
  449. <p>The article <a href="https://solar.lowtechmagazine.com/2018/09/how-to-build-a-lowtech-website/">‘How To Build A Low-Tech Website?’</a> gives more insights into the motivations on making a self-hosted solar-powered server, while this companion article on will give in-depth technical information. </p>
  450. <p>Both the articles and the readesign should be read as a proposition how things could be done, but also as a question on <a href="#room-for-improvements">what could be improved</a>. So we really appreciate additional insights and feedback.</p>
  451. <h1 id="software">Software</h1>
  452. <h2 id="operating-system">Operating system</h2>
  453. <p>The webserver is running on <a href="https://www.armbian.com/olimex-lime-2/">Armbian Stretch</a>, which is a <a href="https://www.debian.org/">Debian</a> based distribution built around the <a href="http://linux-sunxi.org/Main_Page">SUNXI</a> kernel. This is kernel for low-powered AllWinner-based single board computers. The Armbian project provides good documentation on how write an Armbian image to an SD card an boot the board for the first time in the <a href="https://docs.armbian.com/User-Guide_Getting-Started/">Armbian User Guide</a>.</p>
  454. <h2 id="pelican-static-site-design">Pelican Static Site &amp; Design</h2>
  455. <p>The main change in the webdesign was to move from a dynamic website based on Typepad<sup id="fnref:typepad"><a class="footnote-ref" href="#fn:typepad" rel="footnote">1</a></sup> to a static site generated by <a href="https://blog.getpelican.com/">Pelican</a>. Static sites load faster and require less processing than dynamic websites. This is because the pages are pre-generated and read off the disk, rather than being generated on every visit.<sup id="fnref:static"><a class="footnote-ref" href="#fn:static" rel="footnote">2</a></sup></p>
  456. <p>You can find the source code for ‘solar’, the Pelican theme we developed <a href="https://github.com/lowtechmag/solar">here</a></p>
  457. <h3 id="image-compression">Image compression</h3>
  458. <p>One of the main challenges was to reduce the overall size of the website. Particularly to try and reduce the size of each page to something less than 1MB . Since a large part of both the appeal and the weight of the magazine comes from the fact it is richly illustrated, this presented us with a particular challenge. </p>
  459. <p class="img"><img alt="Image from the blog showing 19th century telephone switchboard operators, 159.5KB" src="/images/international-switchboard.jpg"/></p>
  460. <p class="caption">Image from the blog showing 20th century telephone switchboard operators(<a href="https://commons.wikimedia.org/wiki/File:Bell_System_switchboard.jpg">original source</a>), 159.5KB</p>
  461. <p>In order to reduce the size of the images, without diminishing their role in the design and the blog itself, we reverted to a technique called dithering:</p>
  462. <p class="img"><img alt="The same image but dithered with a 3 color palette" src="/images/international-switchboard3.png"/></p>
  463. <p class="caption">The same image but dithered with a 3 color palette, 36.5KB</p>
  464. <p>This is a technique ‘to create the illusion of “color depth” in images with a limited color palette’<sup id="fnref:illusion"><a class="footnote-ref" href="#fn:illusion" rel="footnote">3</a></sup>. It based on the print reproduction technique called <a href="https://en.wikipedia.org/wiki/Halftone">halftoning</a>. Dithering, or digital half-toning<sup id="fnref:digitalhalftone"><a class="footnote-ref" href="#fn:digitalhalftone" rel="footnote">4</a></sup>, was widely used in video games and pixel art at a time when a limited amount of video memory constrained the available colors. In essence dithering relies on optical illusions to simulate more colors. These optical illusions are broken however by the distinct and visible patterns that the dithering algorithms generate. </p>
  465. <p class="img"><img alt="Dithered with a six tone palette" src="/images/international-switchboard6.png"/></p>
  466. <p class="caption">Dithered with a six tone palette, 76KB</p>
  467. <p>As a consequence most of the effort and literature on dithering is around limiting the ‘banding’ or visual artifacts by employing increasingly complex dithering algorithms<sup id="fnref:dithering"><a class="footnote-ref" href="#fn:dithering" rel="footnote">5</a></sup>. </p>
  468. <p>Our design instead celebrates the visible patterns introduced by the technique, this to stress the fact that it is a ‘different’ website. Coincidentally, the ‘Bayesian Ordered Dithering’ algorithm that we use not only introduces these distinct visible patterns, but it is also quite a simple and fast algorithm.</p>
  469. <p class="img"><img alt="Dithered with an eleven tone color palette" src="/images/international-switchboard11.png"/></p>
  470. <p class="caption">Dithered with an eleven tone palette, 110KB</p>
  471. <p>We chose dithering not only for the compression but also for the aesthetic and reading experience. Converting the images to grayscale and then dithering them allows us to scale them in a visually attractive way to 100% of the view port, despite their small sizes. This gives each article a visual consistency and provides the reader with pauses in the long articles. </p>
  472. <p>To automatically dither the images on the blog we wrote <a href="https://github.com/lowtechmag/solar-plugins">a plugin for pelican</a> that converts all source images of the blog. The plugin is based on the <a href="https://pillow.readthedocs.io/en/5.2.x/#">Python Pillow</a> imaging library and <a href="https://github.com/hbldh/hitherdither">hitherdither</a>, a dithering palette library by <a href="https://blog.hbldh.se/">Henrik Blidh</a>. </p>
  473. <p>Using this custom plug-in we reduced the total weight of the 623 images that are on the blog so far by 89%. From 194.2MB to a mere 21.3MB.</p>
  474. <h3 id="archiving-and-portability">Archiving and portability</h3>
  475. <p>Another reason to switch to a static site generator was to be able to ensure an off-line workflow, where the articles can be written and previewed locally in the browser. For this to happen the articles had to be converted to <a href="https://en.wikipedia.org/wiki/Markdown">Markdown</a>, a light weight markup language based on plain text files.</p>
  476. <p>While this is quite a bit of work to do with an archive that spans 10 years of writing, it ensures the portability of the archive for future redesigns or other projects. It also makes it possible for us to archive and version the entire blog using the <a href="https://git-scm.com/doc">git</a> versioning system.</p>
  477. <h3 id="off-line-archive">Off-line archive</h3>
  478. <p>Because we designed the system to have an uptime of only 90% it is expected to go off-line 35 days a year. </p>
  479. <p>Increasing the uptime of the server to 99% on solar energy means increasing the website’s ecological footprint by adding more and more tech in the form of extra solar panels, massively increased battery capacity or extra servers in different geographic locations. </p>
  480. <p>Rather than that we opted for a low-tech approach that accepts being off-line during longer stretches of cloudy weather. However, we wanted to provide the reader with off-line reading options. Our primary method of doing so currently is by providing an <a href="https://solar.lowtechmagazine.com/feeds/all.rss.xml">RSS feed containing all the articles and images on the site</a>. In the future we will explore other means of providing off-line reading of the magazine.</p>
  481. <p class="img"><img alt="An image of the built-in feed reader of Firefox showing solar.lowtechmagazine.com's RSS feed" src="/images/off-line-reading.png"/></p>
  482. <p class="caption"> Most browsers preview only the article titles and summaries of the RSS feed. In fact the feed contains the full articles. Once you add the feed to your favorite reader, it will download the full articles that you can read at any given time. </p>
  483. <h2 id="material-server">Material Server</h2>
  484. <blockquote>
  485. <p>”[…] the minimal file-based website is contrary to a cloud mentality, where the material circumstances of the hardware and hosting location are made irrelevant (for the cloud/vps customer) meaning that any ‘service’ can be ‘deployed’, ‘scaled’ ‘migrated’ etc. Our approach instead informs what can be hosted based on the material circumstances of the server.”<sup id="fnref:varia"><a class="footnote-ref" href="#fn:varia" rel="footnote">6</a></sup></p>
  486. </blockquote>
  487. <p>One of the page’s fundamental design elements is to stress the materiality of the webserver. In web design there is a clear distinction between ‘front-end’, the visual and content side of the website and the ‘back-end’, the infrastructure it runs on top. Outside of professional circles, the material conditions of the web or the internet’s infrastructure are rarely discussed. This has become especially the case with cloud computing as the dominant paradigm, as resources are taken for granted or even completely virtualised.</p>
  488. <p>A low-tech website means this distinction between front-end and back-end needs to disappear as choices on the front-end necessarily impact what happens on the back-end and vice-versa. Ignoring this connection usually leads to more energy usage.</p>
  489. <p>An increase in traffic for example will have an impact on the amount of energy the server uses, just as a heavy or badly designed website will. Part of <a href="https://solar.lowtechmagazine.com">solar.lowtechmagazine.com</a>‘s design aims to give the visitor an insight in the amount of power consumed and the potential (un)availability of the page in the coming days, based on current power usage and forecasts of the weather.</p>
  490. <p>The power statistics can actually be queried from the server hardware. More on that <a href="#server">below</a>. To make the statistics available to the web site we wrote <a href="https://github.com/lowtechmag/materialserver">a bash script</a> that exposes them as JSON in the webroot.</p>
  491. <p>To activate this feature there is a <code>cron</code> entry that runs the script every minute and writes it into the web directory:</p>
  492. <div class="codehilite"><pre><span></span><span class="go">*/1 * * * * /bin/bash /home/user/stats.sh &gt; /var/www/html/api/stats.json</span>
  493. </pre></div>
  494. <h2 id="configuring-the-webserver">Configuring the webserver</h2>
  495. <p>As a webserver we use <a href="https://www.nginx.com/">NGINX</a> to serve our static files. However we made a few non-standard choices to further reduce the energy consumption and page loading times on (recurrent) visits. </p>
  496. <p>To test some of the assumed optimizations we’ve done some measurements using a few different articles. We’ve used the following pages:</p>
  497. <p><code>FP</code> = <a href="https://solar.lowtechmagazine.com">Front page</a>, 404.68KB, 9 images</p>
  498. <p><code>WE</code> = <a href="https://solar.lowtechmagazine.com/2017/09/how-to-run-the-economy-on-the-weather/">How To Run The Economy On The Weather</a>, 1.31 MB, 21 images</p>
  499. <p><code>HS</code> = <a href="https://solar.lowtechmagazine.com/2017/03/heat-storage-hypocausts-air-heating-middle-ages/">Heat Storage Hypocausts</a>, 748.98KB, 11 images</p>
  500. <p><code>FW</code> = <a href="https://solar.lowtechmagazine.com/2015/12/fruit-walls-urban-farming/">Fruit Walls: Urban Farming in the 1600s</a>, 1.61MB, 19 images</p>
  501. <p><code>CW</code> = <a href="https://solar.lowtechmagazine.com/2011/12/the-chinese-wheelbarrow/">How To Downsize A Transport Network: Chinese Wheelbarrows</a>, 996.8KB, 23 images</p>
  502. <p>For this test the pages which are hosted in Barcelona have been loaded from a machine in the Netherlands. The indicated times are all the averages of 3 measurements.</p>
  503. <h3 id="compression-of-transmitted-data">Compression of transmitted data</h3>
  504. <p>We run gzip compression on all our text-based content, this lowers the size of transmitted information at the cost of a slight increase in required processing. By now this is common practice in most web servers but we enable it explicitly. Reducing the amount of data transferred will also reduce the total environmental footprint.</p>
  505. <div class="codehilite"><pre><span></span><span class="gp">#</span>Compression
  506. <span class="go">gzip on;</span>
  507. <span class="go">gzip_disable "msie6";</span>
  508. <span class="go">gzip_vary on;</span>
  509. <span class="go">gzip_comp_level 6;</span>
  510. <span class="go">gzip_buffers 16 8k;</span>
  511. <span class="go">gzip_http_version 1.1;</span>
  512. <span class="go">gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;</span>
  513. </pre></div>
  514. <p>A comparison of the amount of data sent with gzip compression enabled or disabled:</p>
  515. <div class="codehilite"><pre><span></span>|GZIP | MP | WE | HS | FW | CW |
  516. |----------|----------|----------|----------|----------|----------|
  517. | disabled | 116.54KB | 146.08KB | 127.09KB | 125.36KB | 138.28KB |
  518. | enabled | 39.6KB | 51.24KB | 45.24KB | 45.77KB | 50.04KB |
  519. | savings | 64% | 65% | 66% | 66% | 64% |
  520. </pre></div>
  521. <h3 id="caching-of-static-resources">Caching of static resources</h3>
  522. <p>Caching is a technique in which some of the site’s resources, such as style sheets and images, are provided with additional headers that tell the visitor’s browser to save a local copy of those files. This ensures that the next time they visit the same page, the files are loaded from the local cache rather than being transmitted over the network again. This not only reduces the time to load the entire page, but also lowers resource usage both on the network and on our server.</p>
  523. <p>The common practice is to cache everything except the HTML, so that when the user loads the web page again the HTML will notify the browser of all the changes. However since lowtechmagezine.com publishes only 12 articles per year, we decided to also cache HTML. The cache is set for one day, meaning it is only after a week that the user’s browser will automatically check for new content. Only for the front and about pages this behaviour is disabled.</p>
  524. <div class="codehilite"><pre><span></span><span class="go">map $sent_http_content_type $expires {</span>
  525. <span class="go"> default off;</span>
  526. <span class="go"> text/html 1d;</span>
  527. <span class="go"> text/css max;</span>
  528. <span class="go"> application/javascript max;</span>
  529. <span class="go"> ~image/ max;</span>
  530. <span class="go">}</span>
  531. </pre></div>
  532. <p>Concretely this had the following effects:</p>
  533. <p>The first time a page is loaded (FL) it around one second to fully load the page. The second time, however, the file is loaded from the cache and the load time reduced by 40% on average. Since load time are based on the time it takes to load resources over the network and the time it takes for the browser to render all the styling, caching can really decrease load times. </p>
  534. <div class="codehilite"><pre><span></span>| Time(ms) | FP | WE | HS | FW | CW |
  535. |----------|-------|--------|-------|--------|--------|
  536. | FL | 995ms | 1058ms | 956ms | 1566ms | 1131ms |
  537. | SL | 660ms | 628ms | 625ms | 788ms | 675ms |
  538. | savings | 34% | 41% | 35% | 50% | 40% |
  539. </pre></div>
  540. <p>In terms of data transferred the change is even more radical, essentially meaning that no data is transferred the second time a page is visited.</p>
  541. <div class="codehilite"><pre><span></span>| KBs | FP | WE | HS | FW | CW |
  542. |----------|----------|-----------|----------|-----------|----------|
  543. | FL | 455.86KB | 1240.00KB | 690.48KB | 1610.00KB | 996.21KB |
  544. | SL | 0.38KB | 0.37KB | 0.37KB | 0.37KB | 0.38KB |
  545. | savings | &gt;99% | &gt;99% | &gt;99% | &gt;99% | &gt;99% |
  546. </pre></div>
  547. <p>In case you want to force the browser to load cached resources over the network again, do a ‘hard refresh’ by pressing <code>ctrl+r</code></p>
  548. <h3 id="http2-a-more-efficient-hyper-text-transfer-protocol">HTTP2, a more efficient hyper text transfer protocol.</h3>
  549. <p>Another optimization is the use of <a href="https://http2.github.io/">HTTP2</a> over HTTP/1.1. This is a relatively recent protocol that increases the transport speed of the data. This increase is the result of HTTP2 compressing the packet data headers and multiplexing multiple requests into a single TCP connection. In other words, it produces less overhead data and needs to opens less connections between the server and the browser. </p>
  550. <p>The effect of this is most notable when the browser needs to do a lot of different requests, since these can all be fit into a single connection. In our case that specifically means that articles with more images will load slightly faster over HTTP2 than over HTTP/1.1.</p>
  551. <div class="codehilite"><pre><span></span>| | FP | WE | HS | FW | CW |
  552. |----------|-------|-------|-------|-------|-------|
  553. | HTTP/1.1 | 1.46s | 1.87s | 1.54s | 1.86s | 1.89s |
  554. | HTTP2 | 1.30s | 1.49s | 1.54s | 1.79s | 1.55s |
  555. | Images | 9 | 21 | 11 | 19 | 23 |
  556. | savings | 11% | 21% | 0% | 4% | 18% |
  557. </pre></div>
  558. <p>Not all browsers support HTTP2 but the NGINX implementation will automatically serve the files over HTTP/1.1 for those browsers.</p>
  559. <p>It is enabled at the start of the server directive:</p>
  560. <div class="codehilite"><pre><span></span><span class="go">server{</span>
  561. <span class="go"> listen 443 ssl http2;</span>
  562. <span class="go">}</span>
  563. </pre></div>
  564. <h3 id="serve-the-page-over-https">Serve the page over HTTPS</h3>
  565. <p>Even though the website has no dynamic functionality like login forms, we have also implemented SSL to provide Transport Layer Security. We do this mostly to improve page rankings in search engines.</p>
  566. <p>There is something to be said in favour of supporting both HTTP and HTTPS versions of the website but in our case that would mean more redirects or maintaining two versions of the website.</p>
  567. <p>For this reason we redirect all our traffic to HTTPS via the following server directive:</p>
  568. <div class="codehilite"><pre><span></span><span class="go">server {</span>
  569. <span class="go"> listen 80;</span>
  570. <span class="go"> server_name solar.lowtechmagazine.com;</span>
  571. <span class="go"> location / {</span>
  572. <span class="go"> return 301 https://$server_name$request_uri;</span>
  573. <span class="go"> }</span>
  574. <span class="go">}</span>
  575. </pre></div>
  576. <p>Then we’ve set up SSL with the following tweaks:</p>
  577. <div class="codehilite"><pre><span></span><span class="gp">#</span> Improve HTTPS performance with session resumption
  578. <span class="go">ssl_session_cache shared:SSL:10m;</span>
  579. <span class="go">ssl_session_timeout 180m;</span>
  580. </pre></div>
  581. <p>SSL sessions only expire after three hours meaning that while someone browses the website, they don’t need to renegotiate a new SSL session during this period:</p>
  582. <div class="codehilite"><pre><span></span><span class="gp">#</span> Enable server-side protection against BEAST attacks
  583. <span class="go">ssl_prefer_server_ciphers on;</span>
  584. <span class="go">ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;</span>
  585. </pre></div>
  586. <p>We use a limited set of modern cryptographic ciphers and protocols:</p>
  587. <div class="codehilite"><pre><span></span># Disable SSLv3
  588. ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  589. </pre></div>
  590. <p>We tell the visitors browser to always use HTTPS, in order to reduce the amount of 301 redirects, which might slow down loading times:</p>
  591. <div class="codehilite"><pre><span></span><span class="gp">#</span> Enable HSTS <span class="o">(</span>https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security<span class="o">)</span>
  592. <span class="go">add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";</span>
  593. </pre></div>
  594. <p>We enable OCSP stapling which is quick way in which browsers can check whether the certificate is still active without incurring more round trips to the Certificate Issuer. Most tutorials recommend setting Google’s <code>8.8.8.8</code> and <code>8.8.4.4</code> DNS servers but we don’t want to use those. Instead we chose some servers provided through <a href="https://www.opennic.org">https://www.opennic.org</a> that are close to our location:</p>
  595. <div class="codehilite"><pre><span></span><span class="gp">#</span> Enable OCSP stapling <span class="o">(</span>http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox<span class="o">)</span>
  596. <span class="go">ssl_stapling on;</span>
  597. <span class="go">ssl_stapling_verify on;</span>
  598. <span class="go">ssl_trusted_certificate /etc/letsencrypt/live/solar.lowtechmagazine.com/fullchain.pem;</span>
  599. <span class="go">resolver 87.98.175.85 193.183.98.66 valid=300s;</span>
  600. <span class="go">resolver_timeout 5s;</span>
  601. </pre></div>
  602. <p>Last but not least, we set change the size of the SSL buffer to increase to so-called ‘Time To First Byte’<sup id="fnref:TTFB"><a class="footnote-ref" href="#fn:TTFB" rel="footnote">7</a></sup> which shortens the amount of time between passing between a click and elements changing on the screen:</p>
  603. <div class="codehilite"><pre><span></span><span class="gp">#</span> Lower the buffer size to increase TTFB
  604. <span class="go">ssl_buffer_size 4k;</span>
  605. </pre></div>
  606. <p>The above SSL tweaks are heavily indebted to these two articles by <a href="https://bjornjohansen.no/optimizing-https-nginx">Bjorn Johansen</a> and <a href="https://haydenjames.io/nginx-tuning-tips-tls-ssl-https-ttfb-latency/">Hayden James</a></p>
  607. <h3 id="setting-up-letsencrypt-for-https">Setting up LetsEncrypt for HTTPS</h3>
  608. <p>The above are all the SSL performance tweaks but we still need to get our SSL certificates. We’ll do so using <a href="https://letsencrypt.org/">LetsEncrypt</a>.</p>
  609. <p>First install certbot:</p>
  610. <div class="codehilite"><pre><span></span><span class="go">apt-get install certbot -t stretch-backports</span>
  611. </pre></div>
  612. <p>Then run the command to request a certificate using the webroot authenticator:</p>
  613. <div class="codehilite"><pre><span></span><span class="go">sudo certbot certonly --authenticator webroot --pre-hook "nginx -s stop" --post-hook "nginx"</span>
  614. </pre></div>
  615. <p>Use the <code>certonly</code> directive so it just creates the certificates but doesn’t touch much config.</p>
  616. <p>This will prompt an interactive screen where you set the (sub)domain(s) you’re requesting certificates for. In our case that was <code>solar.lowtechmagazine.com</code>.</p>
  617. <p>Then it will ask for the location of the webroot, which in our case is <code>/var/www/html/</code>. It will then proceed to generate a certificate.</p>
  618. <p>Then the only thing you need to do in your NGINX config is to specify where your certificates are located. This is usually in <code>/etc/letsencrypt/live/domain.name/</code>. In our case it is the following:</p>
  619. <div class="codehilite"><pre><span></span><span class="go">ssl_certificate /etc/letsencrypt/live/solar.lowtechmagazine.com/fullchain.pem;</span>
  620. <span class="go">ssl_certificate_key /etc/letsencrypt/live/solar.lowtechmagazine.com/privkey.pem;</span>
  621. </pre></div>
  622. <h3 id="full-nginx-config">Full NGINX config</h3>
  623. <p>Without further ado:</p>
  624. <div class="codehilite"><pre><span></span><span class="gp">root@solarserver:/var/log/nginx#</span> cat /etc/nginx/sites-enabled/solar.lowtechmagazine.com
  625. <span class="gp">#</span> Expires map
  626. <span class="go">map $sent_http_content_type $expires {</span>
  627. <span class="go"> default off;</span>
  628. <span class="go"> text/html 7d;</span>
  629. <span class="go"> text/css max;</span>
  630. <span class="go"> application/javascript max;</span>
  631. <span class="go"> ~image/ max;</span>
  632. <span class="go">}</span>
  633. <span class="go">server {</span>
  634. <span class="go"> listen 80;</span>
  635. <span class="go"> server_name solar.lowtechmagazine.com;</span>
  636. <span class="go"> location / {</span>
  637. <span class="go"> return 301 https://$server_name$request_uri;</span>
  638. <span class="go"> }</span>
  639. <span class="go">}</span>
  640. <span class="go">server{</span>
  641. <span class="go"> listen 443 ssl http2;</span>
  642. <span class="go"> server_name solar.lowtechmagazine.com;</span>
  643. <span class="go"> charset UTF-8; #improve page speed by sending the charset with the first response.</span>
  644. <span class="go"> location / {</span>
  645. <span class="go"> root /var/www/html/;</span>
  646. <span class="go"> index index.html;</span>
  647. <span class="go"> autoindex off;</span>
  648. <span class="go"> }</span>
  649. <span class="gp"> #</span>Caching <span class="o">(</span>save html pages <span class="k">for</span> <span class="m">7</span> days, rest as long as possible, no caching on frontpage<span class="o">)</span>
  650. <span class="go"> expires $expires;</span>
  651. <span class="go"> location @index {</span>
  652. <span class="go"> add_header Last-Modified $date_gmt;</span>
  653. <span class="go"> add_header Cache-Control 'no-cache, no-store';</span>
  654. <span class="go"> etag off;</span>
  655. <span class="go"> expires off;</span>
  656. <span class="go"> }</span>
  657. <span class="gp"> #</span>error_page <span class="m">404</span> /404.html<span class="p">;</span>
  658. <span class="gp"> #</span> redirect server error pages to the static page /50x.html
  659. <span class="gp"> #</span>error_page <span class="m">500</span> <span class="m">502</span> <span class="m">503</span> <span class="m">504</span> /50x.html<span class="p">;</span>
  660. <span class="gp"> #</span><span class="nv">location</span> <span class="o">=</span> /50x.html <span class="o">{</span>
  661. <span class="gp"> #</span> root /var/www/<span class="p">;</span>
  662. <span class="gp"> #</span><span class="o">}</span>
  663. <span class="gp"> #</span>Compression
  664. <span class="go"> gzip on;</span>
  665. <span class="go"> gzip_disable "msie6";</span>
  666. <span class="go"> gzip_vary on;</span>
  667. <span class="go"> gzip_comp_level 6;</span>
  668. <span class="go"> gzip_buffers 16 8k;</span>
  669. <span class="go"> gzip_http_version 1.1;</span>
  670. <span class="go"> gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;</span>
  671. <span class="gp"> #</span>Caching <span class="o">(</span>save html page <span class="k">for</span> <span class="m">7</span> days, rest as long as possible<span class="o">)</span>
  672. <span class="go"> expires $expires;</span>
  673. <span class="gp"> #</span> Logs
  674. <span class="go"> access_log /var/log/nginx/solar.lowtechmagazine.com_ssl.access.log;</span>
  675. <span class="go"> error_log /var/log/nginx/solar.lowtechmagazine.com_ssl.error.log;</span>
  676. <span class="gp"> #</span> SSL Settings:
  677. <span class="go"> ssl_certificate /etc/letsencrypt/live/solar.lowtechmagazine.com/fullchain.pem;</span>
  678. <span class="go"> ssl_certificate_key /etc/letsencrypt/live/solar.lowtechmagazine.com/privkey.pem;</span>
  679. <span class="gp"> #</span> Improve HTTPS performance with session resumption
  680. <span class="go"> ssl_session_cache shared:SSL:10m;</span>
  681. <span class="go"> ssl_session_timeout 5m;</span>
  682. <span class="gp"> #</span> Enable server-side protection against BEAST attacks
  683. <span class="go"> ssl_prefer_server_ciphers on;</span>
  684. <span class="go"> ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;</span>
  685. <span class="gp"> #</span> Disable SSLv3
  686. <span class="go"> ssl_protocols TLSv1 TLSv1.1 TLSv1.2;</span>
  687. <span class="gp"> #</span> Lower the buffer size to increase TTFB
  688. <span class="go"> ssl_buffer_size 4k;</span>
  689. <span class="gp"> #</span> Diffie-Hellman parameter <span class="k">for</span> DHE ciphersuites
  690. <span class="gp"> #</span> $ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem <span class="m">4096</span>
  691. <span class="go"> ssl_dhparam /etc/ssl/certs/dhparam.pem;</span>
  692. <span class="gp"> #</span> Enable HSTS <span class="o">(</span>https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security<span class="o">)</span>
  693. <span class="go"> add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";</span>
  694. <span class="gp"> #</span> Enable OCSP stapling <span class="o">(</span>http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox<span class="o">)</span>
  695. <span class="go"> ssl_stapling on;</span>
  696. <span class="go"> ssl_stapling_verify on;</span>
  697. <span class="go"> ssl_trusted_certificate /etc/letsencrypt/live/solar.lowtechmagazine.com/fullchain.pem;</span>
  698. <span class="go"> resolver 87.98.175.85 193.183.98.66 valid=300s;</span>
  699. <span class="go"> resolver_timeout 5s;</span>
  700. <span class="go">}</span>
  701. </pre></div>
  702. <h1 id="hardware">Hardware</h1>
  703. <p class="img"><img alt="Image of an A20 Olimex SoC board" src="/images/lime2.png"/></p>
  704. <h3 id="server">Server</h3>
  705. <p>The server itself is an <a href="https://www.olimex.com/Products/OLinuXino/A20/A20-OLinuXino-LIME2/">Olimex Olinuxino A20 Lime 2</a> single board computer.</p>
  706. <p>We chose it because of the quality of the (open source) hardware<sup id="fnref:manual"><a class="footnote-ref" href="#fn:manual" rel="footnote">8</a></sup>, the low power consumption and useful extra components such as the charging circuit based on the <a href="http://dl.linux-sunxi.org/AXP/AXP209_Datasheet_v1.0en.pdf">AXP209 power managment chip</a>. </p>
  707. <p>This chip makes it possible to query power statistics such as current voltage and amperage both from the DC-barrel jack connection and the battery. The maintainers of <a href="https://www.armbian.com/olimex-lime-2/">Armbian</a> exposed these statistics via <code>sysfs</code> bindings in their OS.</p>
  708. <p>In addition to the power statistics the power chip can charge and discharge a Lithium Polimer battery and automatically switch between the battery and DC-barrel connector. This means the battery can then act as an uninterruptible power supply, which helps prevent sudden shutdowns. The LiPo battery used has a capacity of 6600mAh which is about 24 Watt hour.</p>
  709. <p>The server operating system all runs on an SD-card. Not only are these low-powered but also much faster than hard drives. We use high speed Class 10 16GB mirco-sd card. A 16GB card is actually a bit of an overkill considering the operating system is around 1GB and the website a mere 30MB, but considering the price it doesn’t make sense to buy any smaller high-performance cards. </p>
  710. <p class="img"><img alt="" src="/images/sps_close.png"/></p>
  711. <h3 id="network">Network</h3>
  712. <p>The server gets it’s internet access through the existing connection of the home office in Barcelona. This connection is a 100mbit consumer fiber connection with a static IP-adress. </p>
  713. <p>The fiber connection itself is not necessary, especially if you keep your data footprint small, but a fixed IP adress is very handy.</p>
  714. <p>The router is a standard consumer router that came with the internet contract. To make the website available, some settings in the router’s firewall had to be changed. </p>
  715. <p>Using a process called ‘port forwarding’, the following ports had to be forwarded between the external network and the server’s local IP address:</p>
  716. <div class="codehilite"><pre><span></span>Port 80 to 80 for HTTP
  717. Port 443 to 443 for HTTPS
  718. Port 22 to 22 for SSH
  719. </pre></div>
  720. <h1 id="room-for-improvements">Room for improvements?</h1>
  721. <h3 id="os-optimization">OS Optimization</h3>
  722. <p>While the Armbian operating system has all kinds of optimizations for running on a SoC, there probably are still many tweaks that can be made to lower the energy usage. </p>
  723. <p>For example energy savings from disabling some of the hardware such as the the USB-hub? Some tips or insights into this are greatly appreciated!</p>
  724. <h3 id="image-dithering">Image dithering</h3>
  725. <p>We’re looking for suggestions how to further compress the images while maintaining this visual quality. We know PNGs are in theory not optimal for representing images on the web, even though they let us limit the color palette to save bandwidth and produce very crisp dithered images. </p>
  726. <p>We’ve found that saving them as JPEG after dithering in fact increases the file size but perhaps other file formats exist that give is similar quality but have a lighter footprint.</p>
  727. <h3 id="sensible-comments-on-static-sites">Sensible comments on static sites</h3>
  728. <p>Dynamic content such as comments are in theory incompatible with a static site. </p>
  729. <p>At the same time they are a big part of the community of knowledge around lowtechmagazine.com. </p>
  730. <p>The comment box under each article on that site is widely used, but e-mail is equally used (often the comments are then added to the article by the author after moderating).</p>
  731. <p>There are some plugins that might address this such as Bernhard Scheirle’s <a href="https://github.com/getpelican/pelican-plugins/tree/master/pelican_comment_system">‘Pelican Comment System’</a> but these we haven’t tested. </p>
  732. <h3 id="ssl-legacy-browsers">SSL &amp; Legacy browsers</h3>
  733. <p>An open question remains: In what a way would it be possible to further extend the support for older machines and browsers without comprimising on security by using deprecated ciphers? Should we maintain both HTTP and HTTPS versions of the site? </p>
  734. <h1 id="donations">Donations</h1>
  735. <p>As is mentioned on the <a href="https://solar.lowtechmagazine.com/donate/">‘donate’</a> page of the site, advertising trackers are incompatible with the new web site design and we really want to keep Low-Tech Magazine tracker free and sustainable so if you enjoy our work or find our public research useful please consider donating. </p>
  736. </article>
  737. </section>
  738. <nav id="jumpto">
  739. <p>
  740. <a href="/david/blog/">Accueil du blog</a> |
  741. <a href="https://homebrewserver.club/low-tech-website-howto.html">Source originale</a> |
  742. <a href="/david/stream/2019/">Accueil du flux</a>
  743. </p>
  744. </nav>
  745. <footer>
  746. <div>
  747. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  748. <p>
  749. Bonjour/Hi!
  750. Je suis <a href="/david/" title="Profil public">David&nbsp;Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
  751. Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
  752. </p>
  753. <p>
  754. Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
  755. </p>
  756. <p>
  757. Voici quelques articles choisis :
  758. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  759. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  760. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  761. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  762. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  763. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  764. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  765. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  766. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  767. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  768. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  769. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  770. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  771. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  772. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  773. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  774. </p>
  775. <p>
  776. On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
  777. </p>
  778. <p>
  779. Je ne traque pas ta navigation mais mon
  780. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  781. conserve des logs d’accès.
  782. </p>
  783. </div>
  784. </footer>
  785. <script type="text/javascript">
  786. ;(_ => {
  787. const jumper = document.getElementById('jumper')
  788. jumper.addEventListener('click', e => {
  789. e.preventDefault()
  790. const anchor = e.target.getAttribute('href')
  791. const targetEl = document.getElementById(anchor.substring(1))
  792. targetEl.scrollIntoView({behavior: 'smooth'})
  793. })
  794. })()
  795. </script>