{"id":11099,"date":"2024-01-06T01:13:05","date_gmt":"2024-01-06T00:13:05","guid":{"rendered":"https:\/\/monodes.com\/predaelli\/?p=11099"},"modified":"2024-01-06T01:14:25","modified_gmt":"2024-01-06T00:14:25","slug":"how-standard-ebooks-serves-millions-of-requests-per-month-with-a-2gb-vps-or-a-paean-to-the-classic-web-alex-cabal","status":"publish","type":"post","link":"https:\/\/monodes.com\/predaelli\/2024\/01\/06\/how-standard-ebooks-serves-millions-of-requests-per-month-with-a-2gb-vps-or-a-paean-to-the-classic-web-alex-cabal\/","title":{"rendered":"How Standard Ebooks serves millions of requests per month with a 2GB VPS; or, a paean to the classic web &#8211; Alex Cabal"},"content":{"rendered":"\n<p>Source: <em><a href=\"https:\/\/alexcabal.com\/posts\/standard-ebooks-and-classic-web-tech\">How Standard Ebooks serves millions of requests per month with a 2GB VPS; or, a paean to the classic web &#8211; Alex Cabal<\/a><\/em><\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><a href=\"https:\/\/standardebooks.org\">Standard Ebooks<\/a> is a project that takes transcriptions of public domain literature, like the kind typically available at <a href=\"https:\/\/gutenberg.org\">Project Gutenberg<\/a>, and creates beautiful, modern ebooks out of them using a <a href=\"https:\/\/standardebooks.org\/manual\">detailed style manual<\/a>. Volunteers from all over the world work to produce these ebooks, and then we release them free of cost and free of copyright restrictions.<\/p>\n\n\n\n<p>Books that are in the US public domain are typically books that were published at least 95 years ago. (At the time of writing, this means published before 1927.) As you can imagine, we spend a lot of our time working on really, really old books. So why not create a website out of really, really old technology?<\/p>\n\n\n\n<p>In 2021 the Standard Ebooks server served about 1.4 million ebook downloads over 15.5 million page views. That comes out to a little over 1.2 million page views per month, and that <em>excludes requests for our <a href=\"https:\/\/en.wikipedia.org\/wiki\/Open_Publication_Distribution_System\">OPDS<\/a> and RSS feeds<\/em>, which also number in the millions per month. It\u2019s been on the front page of Hacker News at <a href=\"https:\/\/news.ycombinator.com\/item?id=25138534\">least<\/a> <a href=\"https:\/\/news.ycombinator.com\/item?id=20594802\">three<\/a> <a href=\"https:\/\/news.ycombinator.com\/item?id=14570035\">times<\/a> in the past several years without breaking a sweat. And we did all this with a tiny VPS serving a website that has no Javascript\u2014or even a database!<\/p>\n\n\n\n<p>The amount of traffic we get isn\u2019t <em>that<\/em> crazy. But it\u2019s a demonstration of how inexpensive, classic-web technology can serve a surprising amount of traffic, without relying on any of the technological crutches that so many of us reflexively reach for nowadays when starting new projects.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What the SE server does<\/h2>\n\n\n\n<p>SE runs its entire operations using one single-core VPS with 2GB of RAM. It\u2019s responsible for:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Hosting all of the Git repositories for all of our ebooks, serving as the source of truth for the ebooks we produce. (While we also host all of our ebooks on GitHub, <em>GitHub is actually a mirror<\/em>, not the origin, for our ebooks. We think keeping local control is important, and self-hosting a GitHub-like solution to allow the public to view ebook sources and submit corrections, instead of relying on GitHub, is on our long-term roadmap.)<\/li>\n\n\n\n<li>Running the ebook build process when an ebook is released or updated.<\/li>\n\n\n\n<li>Serving the SE website, including the OPDS and RSS feeds.<\/li>\n<\/ol>\n\n\n\n<p>The <a href=\"https:\/\/github.com\/standardebooks\/web\">Standard Ebooks website<\/a> runs on a classic LAP stack. What\u2019s that, you say? LAP? That\u2019s right: LAMP without the M. <em>There isn\u2019t even a traditional database behind the SE website.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why PHP?<\/h2>\n\n\n\n<p>I\u2019ve been writing PHP for almost twenty years now. It\u2019s a language and paradigm I\u2019m familiar with. As one gets older, one feels less and less excitement for the new tech hotness\u2014after all, when one must drive a nail, there\u2019s only so many different kinds of hammers to get excited about before one stops caring and just reaches for the go-to. So when I want to start a new website, I reach for PHP.<\/p>\n\n\n\n<p>Fortunately, PHP is <a href=\"https:\/\/w3techs.com\/technologies\/details\/pl-php\">by one measure the server-side language of choice for 78% of the web<\/a>, so hitching your wagon to such a popular language means it\u2019ll be easy to find someone to maintain it for at least the next few decades.<\/p>\n\n\n\n<p>Modern PHP isn\u2019t half bad, and it has at least two major benefit over some of its competitors:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Each request is a totally independent request that rebuilds the world. There\u2019s no shared state (unless you want there to be).<\/li>\n\n\n\n<li>It\u2019s an interpreted language, so there\u2019s no code to recompile and no servers to restart when deploying. You make a change in your script, save your file, refresh your browser, and there it is. That makes development and debugging <em>really fast<\/em> and deployment <em>really easy<\/em>.<\/li>\n<\/ol>\n\n\n\n<p>What many people also don\u2019t know is that PHP is also a fairly good templating language out of the box! While it\u2019s easy to assume that any PHP web project at the bare minimum requires one of the <a href=\"https:\/\/laravel.com\/\">big<\/a> <a href=\"https:\/\/symfony.com\/\">frameworks<\/a>, in truth it\u2019s easy to use basic PHP as its own simple templating system. For many basic classic-web websites, like SE\u2019s, that\u2019s often enough to get the job done; and the big benefit is that you\u2019re not stuck with having to learn and <em>maintain<\/em> a huge bells-and-whistles 3rd-party framework in perpetuity.<\/p>\n\n\n\n<p>I think people really underestimate the burden of <em>maintaining<\/em> a 3rd-party framework even after <em>development<\/em> of the website is complete. If your website is alive for even just five short years, how many times will you have to update the framework, even if only for security updates, and keep up with API updates to make sure there are no breaking changes? Once is too much for what\u2019s essentially scaffolding that I never want to see again.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How the SE server handles everything without falling over<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Serving a web request<\/h3>\n\n\n\n<p>Requests start at Apache, which usually starts by rewriting the URL using <code class=\"\" data-line=\"\">mod_rewrite<\/code>\u2014for example, rewriting an ebook path into a PHP script with a query string. This is kind of equivalent to the router in a server-side framework, except that it\u2019s done before PHP even enters the picture.<\/p>\n\n\n\n<p>Once Apache decides what PHP script to run, it forwards it to PHP-FPM. <a href=\"https:\/\/php-fpm.org\/\">PHP-FPM<\/a> is the process manager that replaced the ailing and feeble <code class=\"\" data-line=\"\">mod_php<\/code> many years ago, and is one of the major reasons why modern PHP websites can be so fast.<\/p>\n\n\n\n<p>Once a request reaches PHP, we start creating output for the browser using a <a href=\"https:\/\/github.com\/standardebooks\/web\/blob\/master\/lib\/Template.php\">very, very small file-based templating system<\/a>. It uses raw PHP instead of a custom templating syntax. As I mentioned earlier, PHP is already a surprisingly good templating language in its own right. Why reinvent the wheel?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Dynamic content without a database<\/h3>\n\n\n\n<p>At this point in the request, we may have to look up some data before we can present it to the browser. This is where one might query a database\u2014but we don\u2019t have a database. So how do we do it?<\/p>\n\n\n\n<p>You may recall that the SE server also hosts all of the Git repositories for all our ebooks. These ebooks are rich in metadata, including title, author, descriptions, word count, series information, and so on. Because our corpus of ebooks is relatively small (about 630 ebooks at the time of writing), <em>we\u2019re able to fit all of them in memory<\/em>: specifically, using PHP\u2019s built-in <a href=\"https:\/\/www.php.net\/manual\/en\/book.apcu.php\">APCu object cache<\/a>.<\/p>\n\n\n\n<p>This cache survives across PHP processes, so we only have to initialize it once when PHP-FPM first starts, and we only have to update it when an ebook is updated. If the PHP process crashes or the server restarts, the website rebuilds the cache from scratch whenever it starts up again. Building this cache does take a few seconds, but since crashes and restarts are rare it\u2019s not a big deal.<\/p>\n\n\n\n<p>You may be thinking that this is a pretty silly approach to a dynamic website. Why not just use a database?<\/p>\n\n\n\n<p>I don\u2019t entirely disagree. But it\u2019s that way because SE started out as\u2014and in many ways still is\u2014a small hobby project, and small hobby projects want to spend time on the meat (ebooks) and not the potatoes (a website).<\/p>\n\n\n\n<p>To build a website, we would have <em>already<\/em> had to parse the XML in our ebooks, if only to insert it into a database for later lookup. If we\u2019re already creating ebook objects in PHP, why not just skip the database, the ORM layer, the glue code, the data model, and all that ancillary stuff, and simply cache the ebook objects themselves, to save development time on this hobby?<\/p>\n\n\n\n<p>It turned out that for our small data set and very basic data processing requirements, this approach is perfectly performant. Of course, we\u2019ll <em>eventually<\/em> reach a point where we\u2019ll need a real database, but we\u2019ll probably reach that point first because we want our website to do more complex things, not because the size of our ebook corpus calls for one.<\/p>\n\n\n\n<p>And in the meantime, we\u2019re still serving millions of page views just fine.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Javascript not necessary<\/h3>\n\n\n\n<p>If we haven\u2019t shocked you with our deeply-questionable design decisions yet, this one might shock the younger developers out there most of all: our website doesn\u2019t use any Javascript. Zero. (Well, with the exception of a link to a <code class=\"\" data-line=\"\">manifest.json<\/code> file, because there\u2019s no way around that.)<\/p>\n\n\n\n<p>In terms of content, the SE website is very much a classic-web website. There\u2019s a homepage, a search page with a paginated list of items, a detail view of those items, some very basic forms here and there, and a few ancillary, mostly static pages. And it just so happens that plain HTML with some clever CSS has just about all of the functionality needed by that kind of website:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Styling, animations, transitions, and responsive affordances are handled with plain CSS.<\/li>\n\n\n\n<li>Forms are plain HTML that send regular old GET and POST requests via a boring Submit button. We don\u2019t need fancy AJAX or loading spinners\u2014when you click Submit, your web browser probably already shows you a loading spinner somewhere.<\/li>\n\n\n\n<li>There\u2019s no client-side tracking code and there are no ads.<\/li>\n\n\n\n<li>Everything is rendered server-side before it reaches your browser.<\/li>\n<\/ul>\n\n\n\n<p>In just a few short years, server-side rendering went from the near-universal default to a quaint relic, and now Javascript is an \u201cobvious\u201d necessity in a land where everything is an API to be rendered client-side by a huge 3rd-party Javascript framework. But this new paradigm is <em>slow<\/em>: serving megabytes of Javascript is slow, waiting for an API response is slow, parsing the response client-side and generating a page client-side is slow.<\/p>\n\n\n\n<p>To add insult to injury, more often than not <em>you\u2019re doing the work twice:<\/em> Once to parse, assemble, and output data on the server, and again to parse, assemble, and render data on the client.<\/p>\n\n\n\n<p>And JS frameworks, like PHP frameworks, are yet another 3rd-party dependency for you to maintain indefinitely, even if your website is no longer actively updated. How often has a once-popular JS framework faded away, overtaken by the latest hotness?<\/p>\n\n\n\n<p>Not only that, but it\u2019s far easier to output <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Learn\/Accessibility\/HTML\">accessible web pages<\/a> using carefully-chosen, plain HTML at the source, than it is when cobbling together elements after the fact with client-side JS.<\/p>\n\n\n\n<p>JS frameworks do make sense for some larger, <em>very complex apps<\/em>. But so few websites are legitimately <em>very complex apps<\/em>. More often than not, they\u2019re <a href=\"https:\/\/en.wikipedia.org\/wiki\/Create,_read,_update_and_delete\">just another CRUD app<\/a>\u2014the kind of document-based, asynchronous model that the classic web was designed and built for.<\/p>\n\n\n\n<p>And while it may seem faster to develop a new project by starting with a JS framework, it may be just as fast to develop a new project starting from a server-side framework for your language of choice.<\/p>\n\n\n\n<p>I\u2019m not an anti-JS zealot. Judicious use of Javascript can most definitely enhance the user experience. But does the whole thing need to be done in React? Or could a few carefully-placed lines of jQuery\u2014or even vanilla JS\u2014do the job? Does your CRUD app <em>need<\/em> to be a single-page JS app delivered over websockets?<\/p>\n\n\n\n<p>For SE\u2014a very classic-web project\u2014eschewing Javascript, rendering server-side, and relying on the classic web\u2019s model of static documents and basic forms for interactivity not only reduces our maintenance burden and greatly simplifies development, but it also speeds up the user experience and improves accessibility to boot.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cloud not necessary, either<\/h3>\n\n\n\n<p>These days, it\u2019s very popular to start even a basic website on a cloud service like AWS or Azure. But while the company hosting our VPS is technically a cloud service\u2014admittedly, our desire to be self-sufficient ends just before owning bare metal in a rented rack\u2014we don\u2019t rely on any other 3rd-party cloud service like AWS or Azure.<\/p>\n\n\n\n<p>Part of the reason is because just glancing at the <a href=\"https:\/\/docs.aws.amazon.com\/general\/latest\/gr\/glos-chap.html\">dizzying list of AWS acronyms and initialisms<\/a> makes me light-headed and woozy.<\/p>\n\n\n\n<p>But the more serious reason is that SE, as a kind of classic-web project, aspires to be independent, just like the classic web once was. Our big external dependency is currently GitHub, but our (very) long-term goal is to drop that too in favor of a self-hosted Git interface.<\/p>\n\n\n\n<p>Starting on a cloud provider cedes one\u2019s independence because it often leads to vendor lock-in. For example, once you start with AWS and its eldritch coterie of inscrutible services, you start requiring specialized, proprietary knowledge\u2014how do I set permissions on an S3 bucket again?\u2014and it can be pretty tough to dig an established project out of that. What if you wanted to change your hosting provider, or your storage or backup solution?<\/p>\n\n\n\n<p>The big benefit of running a basic Linux box on our own VPS is that everything is just files on a generic, well-understood platform. For the most part, Ubuntu at one host is going to be the same as Ubuntu on another one, and Ubuntu is Linux so jumping to (say) CentOS isn\u2019t a huge leap. These skills are highly transferable, making it much easier to move a project somewhere else, or upgrade a server if our needs outgrow its muscle.<\/p>\n\n\n\n<p>Lots of people also choose a cloud service because their CDNs can improve request speed. While that\u2019s certainly true, SE\u2019s classic-web approach makes that much less important. Modern web apps have grown to be so bloated in asset size, and spend so much time processing JS, that using a CDN to shave a few milliseconds off of fetching a static asset becomes a lot more valuable to them. But since we carefully control the size and amount of static assets we serve, and just send complete pages back to the client instead of relying on JS to render a page, shaving milliseconds all of a sudden seems much less important. And if the website\u2019s a touch slower at geographic locations far from our host, well, we\u2019re serving free ebooks here\u2014it\u2019s not life-or-death.<\/p>\n\n\n\n<p>Cloud providers have their place for a lot of computing tasks, and start making more sense once a project starts reaching a <em>very<\/em> large scale. But for serving a basic website and the attendant infrastructure that that requires\u2014up to a perhaps-surprising amount of traffic\u2014a VPS is a low-cost, simple, and lock-in-free way to go. Very classic-web.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">It\u2019s just files in a filesystem<\/h3>\n\n\n\n<p>For most basic websites, the biggest resource consumer besides the database is usually the server-side language assembling the web page to serve. Web servers are very, very fast when serving plain files on a filesystem that don\u2019t require any server-side processing.<\/p>\n\n\n\n<p>With that in mind, we\u2019ve made it so that most of the files the SE server serves are static files residing on a regular filesystem. Our OPDS and RSS feeds are static files that are only re-generated when a book is updated; ebook downloads are plain files in a folder, and so are their read-online versions; and so on.<\/p>\n\n\n\n<p>It can be tempting to serve downloads via a script that does a database lookup, or regenerate a feed for each request. But that\u2019s a lot of work when plain files on a filesystem are so performant. Keeping the website as a bunch of mostly-static files is not only a really fast, very classic way of organizing a website, but it also gives us the benefit of&#8230;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Easy deployment<\/h3>\n\n\n\n<p>Because PHP isn\u2019t precompiled and because we have no Javascript or CSS to transpile or minify, deploying the website is as easy as <a href=\"https:\/\/linux.die.net\/man\/1\/rsync\"><code class=\"\" data-line=\"\">rsync<\/code><\/a>.<\/p>\n\n\n\n<p>A single <code class=\"\" data-line=\"\">rsync<\/code> invocation pushes our development filesystem into production, creating, updating, and deleting files to make the two filesystems match, and voila\u2014our changes are live.<\/p>\n\n\n\n<p>This paradigm of a website being just a collection of files is becoming more and more unusual as language and frameworks are accumulating increasingly-esoteric compilation processes and package managers. Is my NPM version up to date? Did we write the correct XML scaffolding to compile the right DLLs? Did we transpile the Typescript before minifying it into a Yarn package? Did Bower clone the right library into Jekyll before crombulating the monorepo? Who cares! All we have to do is copy our filesystem over and it Just Works.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building ebooks<\/h3>\n\n\n\n<p>The SE server is also responsible for building ebooks when they get released or updated. This is done using our <a href=\"https:\/\/github.com\/standardebooks\/tools\">ebook production command line toolset<\/a>. Every time an ebook repository is updated, a Git hook kicks off a rebuild of the ebook so that the updated version can be served on the website.<\/p>\n\n\n\n<p>Building an ebook can be fairly slow and resource-heavy for several reasons, and it\u2019s even slower on our low-resource VPS. The VPS can comfortably build one ebook at a time while also serving the website, but more than say, three, ebooks building at once can cause the server to gasp for air and claw frantically at its chest.<\/p>\n\n\n\n<p>To stop this from happening, builds are queued using <a href=\"https:\/\/manpages.ubuntu.com\/manpages\/xenial\/man1\/tsp.1.html\">Task Spooler, or <code class=\"\" data-line=\"\">ts<\/code><\/a>, a program that manages a queue of Bash scripts, executes them sequentially, and records their output. <code class=\"\" data-line=\"\">ts<\/code> is a small, simple, Unix-y way to make sure that frequent updates to a series of ebooks don\u2019t overtax our limited resouces with a bunch of build tasks all at once, while at the same time avoiding the overkill of a much larger, all-in-one solution like Beanstalk.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Side note: XHTML<\/h3>\n\n\n\n<p>One quirk of the SE website unrelated to performance is that it serves XHTML5.<\/p>\n\n\n\n<p>XHTML is the overlooked sibling of HTML5, and the herald of the fabled semantic web of the mid\u2013early-2000s. It brings with it all of the tedious, groan-inducing baggage of XML, like namespaces and brutal parser errors, but with only minor benefits that go mostly to the rendering engine, and not much else.<\/p>\n\n\n\n<p>It never took off on the web, in part because in a website context so much HTML is generated by templates and libraries that it\u2019s all too easy to introduce a syntax error somewhere along the line; and unlike HTML, where a syntax error would still render <em>something<\/em>, the tiniest syntax error in XHTML means the whole thing gets thrown out by the browser and you get the Yellow Screen of Death.<\/p>\n\n\n\n<p>But even though XHTML isn\u2019t popular in the web, it still lives in on in one very big space: ebooks.<\/p>\n\n\n\n<p>You see, <a href=\"https:\/\/en.wikipedia.org\/wiki\/EPUB\">EPUB<\/a>, the surprisingly excellent (how often would you describe a standard as \u201cexcellent\u201d?) open ebook format used by the vast majority of ebook producers and reading systems, is basically a set of XML\/XHTML files bundled up in a zip file. You could unzip an ebook and open its XHTML files in your web browser, and it would look just like a regular web page.<\/p>\n\n\n\n<p>Since our stock in trade is zip files containing XHTML, we figured why not serve the website itself as XHTML too, as a whimsical nod to our ebook roots? So we did.<\/p>\n\n\n\n<p>I wouldn\u2019t really recommend you serve XHTML if you\u2019re starting a new project. It\u2019s unforgiving, with few or no benefits. But for us, it\u2019s a kind of fun experiment, something a project manager wouldn\u2019t let you do in real life\u2014a tribute to our beloved EPUB format, and a raise of the glass to the halcyon dream of the semantic web.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why does this all matter?<\/h2>\n\n\n\n<p>All of this goes to show that you don\u2019t need a whole lot to build a performant, useful website, capable of serving millions of requests a month, on a tiny server that also handles other resource-intensive tasks.<\/p>\n\n\n\n<p>It\u2019s a fallacy to think that bloated JS frameworks, complex back-end frameworks, a galaxy of package managers, elaborate moving parts like databases or specialized queueing software, and hyper-resourced, expensive cloud instances at proprietary vendors are needed to create a \u201cmodern\u201d website. Classic-web techniques can get you serving millions of page views for pennies per month. <em>And you get speed, accessibility, maintainability, and simplicity for free.<\/em><\/p>\n\n\n\n<p>Next time you\u2019re thinking of adding a JS library to animate an element, ask yourself: Can I do this with plain CSS?<\/p>\n\n\n\n<p>Next time you\u2019re starting a new website with React, ask yourself: What if I just rendered server side?<\/p>\n\n\n\n<p>Next time you\u2019re spinning up a compute instance on a proprietary cloud provider, ask yourself: Would a $5 VPS do?<\/p>\n\n\n\n<p>And next time you\u2019re feeling like serving XHTML5, ask yourself: Hold on a minute, <em>what<\/em>?<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p class=\"excerpt\">Source: How Standard Ebooks serves millions of requests per month with a 2GB VPS; or, a paean to the classic web &#8211; Alex Cabal<\/p>\n<p class=\"more-link-p\"><a class=\"more-link\" href=\"https:\/\/monodes.com\/predaelli\/2024\/01\/06\/how-standard-ebooks-serves-millions-of-requests-per-month-with-a-2gb-vps-or-a-paean-to-the-classic-web-alex-cabal\/\">Read more &rarr;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-11099","post","type-post","status-publish","format-standard","hentry","category-senza-categoria"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6daft-2T1","jetpack-related-posts":[{"id":6686,"url":"https:\/\/monodes.com\/predaelli\/2020\/02\/23\/e-ink-book-readers\/","url_meta":{"origin":11099,"position":0},"title":"e-ink book readers","author":"Paolo Redaelli","date":"2020-02-23","format":false,"excerpt":"As a society, we need an open source device for reading. Books are among the most important documents of our culture, yet the most popular and widespread devices we have for reading \u2014 the Kobo, the Nook, the Kindle and even the iPad \u2014 are closed devices, operating as small\u2026","rel":"","context":"In &quot;Hardware&quot;","block_context":{"text":"Hardware","link":"https:\/\/monodes.com\/predaelli\/category\/hardware\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2020\/02\/book-rev4.jpg?fit=1200%2C900&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2020\/02\/book-rev4.jpg?fit=1200%2C900&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2020\/02\/book-rev4.jpg?fit=1200%2C900&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2020\/02\/book-rev4.jpg?fit=1200%2C900&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2020\/02\/book-rev4.jpg?fit=1200%2C900&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":11676,"url":"https:\/\/monodes.com\/predaelli\/2024\/05\/26\/how-to-wirelessly-send-docs-and-e-books-to-your-kobo\/","url_meta":{"origin":11099,"position":1},"title":"How to wirelessly send docs and e-books to your Kobo","author":"Paolo Redaelli","date":"2024-05-26","format":false,"excerpt":"As we are a family of avid readers, having the luck of having a public library very near our house, we also ended up having several Kobo ebook readers. I'm a life-long user of free-as-in-freedom software and I like to meddle with \"low level\" thingies but I can't ask my\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/monodes.com\/predaelli\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2024\/05\/wp-17167394545158690451497620684265.jpg?fit=384%2C640&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":14101,"url":"https:\/\/monodes.com\/predaelli\/2025\/10\/08\/njal-la\/","url_meta":{"origin":11099,"position":2},"title":"njal.la","author":"Paolo Redaelli","date":"2025-10-08","format":false,"excerpt":"njal.laConsidered the worlds most notorious \"Privacy as a Service\" provider for domains, VPS' and VPNs.","rel":"","context":"In &quot;Senza categoria&quot;","block_context":{"text":"Senza categoria","link":"https:\/\/monodes.com\/predaelli\/category\/senza-categoria\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":14772,"url":"https:\/\/monodes.com\/predaelli\/2026\/01\/20\/mythic-beasts\/","url_meta":{"origin":11099,"position":3},"title":"Mythic Beasts","author":"Paolo Redaelli","date":"2026-01-20","format":false,"excerpt":"Mythic Beasts Managed and unmanaged VPS and dedicated servers, shared web and email hosting, domain registrations and DNS hosting, UK based","rel":"","context":"In &quot;Senza categoria&quot;","block_context":{"text":"Senza categoria","link":"https:\/\/monodes.com\/predaelli\/category\/senza-categoria\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2055,"url":"https:\/\/monodes.com\/predaelli\/2017\/01\/06\/exiting-the-ivory-tower\/","url_meta":{"origin":11099,"position":4},"title":"Exiting the ivory tower","author":"Paolo Redaelli","date":"2017-01-06","format":false,"excerpt":"From \"Web Development with Bootstrap 4 and Angular 2 - Second Edition\" In one moment of compilation, a TypeScript compiler can generate a declaration file which contains only signatures of the exported types. The resulting declaration file with the extension .d.ts along with a JavaScript library or module can be\u2026","rel":"","context":"In &quot;Eiffel&quot;","block_context":{"text":"Eiffel","link":"https:\/\/monodes.com\/predaelli\/category\/eiffel\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":10226,"url":"https:\/\/monodes.com\/predaelli\/2023\/02\/14\/how-to-join-a-linux-system-to-an-active-directory-domain\/","url_meta":{"origin":11099,"position":5},"title":"How to join a Linux system to an Active Directory domain","author":"Paolo Redaelli","date":"2023-02-14","format":false,"excerpt":"Do you need to centrally manage Linux systems and user accounts under an Active Directory domain? Here's how to do it. Source: How to join a Linux system to an Active Directory domain You will end up having a \/etc\/sssd\/sssd.conf file like this [sssd] domains = YOUR_DOMAIN config_file_version = 2\u2026","rel":"","context":"In &quot;Proprietary software&quot;","block_context":{"text":"Proprietary software","link":"https:\/\/monodes.com\/predaelli\/category\/software\/proprietary-software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2023\/02\/sudols10.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2023\/02\/sudols10.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2023\/02\/sudols10.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2023\/02\/sudols10.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2023\/02\/sudols10.png?resize=1050%2C600&ssl=1 3x"},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/11099","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/comments?post=11099"}],"version-history":[{"count":0,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/11099\/revisions"}],"wp:attachment":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/media?parent=11099"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/categories?post=11099"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/tags?post=11099"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}