384 lines
59 KiB
Plaintext
Executable File
384 lines
59 KiB
Plaintext
Executable File
a:6:{s:5:"child";a:1:{s:0:"";a:1:{s:3:"rss";a:1:{i:0;a:6:{s:4:"data";s:6:"
|
|
|
|
";s:7:"attribs";a:1:{s:0:"";a:1:{s:7:"version";s:3:"2.0";}}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:1:{s:7:"channel";a:1:{i:0;a:6:{s:4:"data";s:317:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:2:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:19:"LinuxServer.io Blog";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:31:"https://www.linuxserver.io/blog";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:13:"Posts n stuff";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"language";a:1:{i:0;a:5:{s:4:"data";s:2:"en";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:13:"lastBuildDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Mon, 16 Dec 2024 15:00:00 +0000";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"item";a:10:{i:0;a:6:{s:4:"data";s:231:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:25:"New and Improved For 2025";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:57:"https://www.linuxserver.io/blog/new-and-improved-for-2025";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:57:"https://www.linuxserver.io/blog/new-and-improved-for-2025";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Mon, 16 Dec 2024 15:00:00 +0000";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:3644:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/1/6/3/5/c/1635c557246d95f12193c7ffbaac66df232ada76-fireworks11jgoisgc7.jpg" />
|
|
<p>As we approach the end of the year we thought we would take the opportunity to take a look back at some of the things we've achieved in 2024 and how they benefit you now and in 2025. A lot of the changes we make to our pipelines and images take a while to actually reach end users, both because of the time it takes for us to roll them out across our fleet and because some users don't regularly update their containers. So, what have we done and what does it mean for you? Well:</p>
|
|
<h3>Images</h3>
|
|
<h4>Software Bill of Materials</h4>
|
|
<p><a href="https://docs.docker.com/build/metadata/attestations/sbom/">Software Bill of Materials (SBOM) Attestations for Docker images</a> describe what software artifacts an image contains, and artifacts used to create the image. We have for a long time published a package_versions.txt file in each image repo listing all the software included as part of the container, but it was hard for users to know for sure that it was an accurate reflection of the actual image, or to validate it for older images they might be using.</p>
|
|
<p>Now that we're publishing SBOM attestations as part of the images, you can view them for any image tag going forward by doing something like <code>docker buildx imagetools inspect lscr.io/linuxserver/plex:latest --format '{{ json (index .SBOM "linux/amd64").SPDX }}</code>, adjusting the architecture to match yours. If you're pulling an arch-specific tag you can instead do something like <code>docker buildx imagetools inspect lscr.io/linuxserver/socket-proxy:arm64v8-latest --format '{{ json .SBOM.SPDX }}'</code>. You can then use a tool like Syft to convert the SPDX JSON manifest into something more human-readable e.g. <code>syft convert SBOM.json -o table=./package_versions.txt</code>.</p>
|
|
<p>Please note there are a few images that cannot currently support SBOM attestation but we're working to get them into a position where they can.</p>
|
|
<h4>Provenance</h4>
|
|
<p>In a similar vein, <a href="https://docs.docker.com/build/metadata/attestations/slsa-provenance/">Provenance Attestations for Docker images</a> include facts about the build process, allowing you to see exactly how and when they were built. Again, we already made a lot of this public via our <a href="https://ci.linuxserver.io/">CI</a> but it was hard to link a specific build run to any given image you might be using.</p>
|
|
<p>In the same way as the SBOM attestations you can view Provenance details for any image tag going forward by doing something like <code>docker buildx imagetools inspect lscr.io/linuxserver/plex:latest --format '{{ json (index .Provenance "linux/amd64").SLSA }}'</code>, with a similar adjustment for arch-specific tags. Unfortunately we're not aware of any good tools to produce a nice human-readable output for SLSA.</p>
|
|
<p>Please note there are a few images that cannot currently support Provenance attestation but we're working to get them into a position where they can.</p>
|
|
<h4>Read-Only</h4>
|
|
<p>Providing <a href="https://docs.linuxserver.io/misc/read-only">Read Only running of our containers</a> has involved a steep learning curve. It's amazing just how much stuff expects to be able to write to the container filesystem and doesn't provide you any practical way to redirect it. At time of writing, after testing nearly 200 images, and making quite a few modifications to how we handling their init processes, 35...</p>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:5:{i:0;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:4:"news";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:11:"linuxserver";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:4:"sbom";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:4:"slsa";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:1;a:6:{s:4:"data";s:173:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:38:"Better Practices For Docker Networking";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:70:"https://www.linuxserver.io/blog/better-practices-for-docker-networking";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:70:"https://www.linuxserver.io/blog/better-practices-for-docker-networking";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Tue, 08 Oct 2024 13:00:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:3629:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/6/c/7/b/9/6c7b913b1011a565ee2fbc9bfdc0a430527b2983-patch.jpg" />
|
|
<p>Many years ago we wrote a blog post on <a href="https://www.linuxserver.io/blog/2017-10-17-using-docker-networks-for-better-inter-container-communication">Docker networks</a> and how to use them, but that was 2017 and this is now so surely everything has changed?</p>
|
|
<p>Well, not really, <em>but</em> at lot of this stuff is abstracted away by management interfaces and people don't understand what's going on behind the scenes so they make bad decisions that come back to haunt them 6 months down the line. With that in mind we're going to try present a clear idea of what good practice looks like for Docker networking so you can properly plan out your infrastructure and avoid the pain of having to rip everything out again when you run into problems.</p>
|
|
<h3>Docker Network Types</h3>
|
|
<p>There are lots of different types of Docker network available to you:</p>
|
|
<ul>
|
|
<li>None - As you'd expect, no networking at all</li>
|
|
<li>Host - Attach the container directly to the host's network interface</li>
|
|
<li>Macvlan - A virtual host sub-interface with its own IP and MAC addresses on your LAN</li>
|
|
<li>IPvlan - A virtual layer 2 host sub-interface with its own IP addresses on your LAN, or virtual layer 3 interface</li>
|
|
<li>Overlay - A distributed network between multiple Docker Swarm nodes</li>
|
|
<li>(Default) Bridge - The built-in (and <a href="https://docs.docker.com/engine/network/drivers/bridge/#differences-between-user-defined-bridges-and-the-default-bridge">very limited</a>) bridge network. Docker will NAT traffic to/from the host interface</li>
|
|
<li>(User-defined) Bridge - A custom bridge network. Docker will NAT traffic to/from the host interface</li>
|
|
</ul>
|
|
<p>For our purposes today we only care about user-defined bridge networks; there are use cases for Macvlan/IPvlan but they're outside the scope of this post as 99% of the time they're the wrong choice. You can think of a bridge network as its own mini-LAN, with Docker passing traffic in and out via NAT the same way you would with your router.</p>
|
|
<h3>Inter-Container Communication</h3>
|
|
<p>The most important feature of a user-defined bridge network is that it enables DNS name resolution and communication between its containers; if you have your <code>speedtest-tracker</code> container and your <code>speedtest-tracker-db</code> Postgres container on the <code>lsio</code> bridge network you can tell Speedtest Tracker to use <code>speedtest-tracker-db:5432</code> as the database host rather than having to use the host IP, and having to expose ports. You can also control the size of the network, and whether or not it can communicate with your wider LAN/WAN networks. One of the side effects of this is that you no longer have to worry about port conflicts. You can have 50 containers all on the same bridge network, all using port 80, and it doesn't matter. Your reverse proxy is the only thing that needs to expose port 80 (and 443) to the host.</p>
|
|
<p>You can create bridge networks with the Docker <code>docker network create</code> CLI command, but Docker Compose will do all the heavy lifting for you, so let's work with that for our examples.</p>
|
|
<h4>Compose Networking Basics</h4>
|
|
<p>If you don't define any networks in your compose project then it will automatically create a <code><compose project>_default</code> network with default settings and attach all containers in the project to it, but...</p>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:3:{i:0;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:6:"how to";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:10:"networking";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:2;a:6:{s:4:"data";s:202:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:43:"Own Up, Which One of You Broke The Website?";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:73:"https://www.linuxserver.io/blog/own-up-which-one-of-you-broke-the-website";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:73:"https://www.linuxserver.io/blog/own-up-which-one-of-you-broke-the-website";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Mon, 23 Sep 2024 14:30:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:3556:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/4/5/9/a/a/459aa79b0ee87c4c3a9594a95bf5076653575e76-8041388538c35c8c13a1h.jpg" />
|
|
<p>Our infrastructure can be broadly split into three categories: Public Facing, Internal, and Builders.The latter should be pretty self-explanatory and are a mix of amd64 and aarch64 boxes that build all our images. Internal services include things like our wiki, monitoring and metrics, automation, Discord bots, etc. The bulk of our public facing services - our website, Discourse forums, Fleet, Info, and Status pages - are hosted on Digital Ocean droplets, however, we use a number of different hosting providers for our other services, in part because it's wise to distribute your eggs, in part because DO don't offer arm droplets, and in part because running 24/7 droplets of the required number and spec for our builders would simply be more expensive than more traditional hosting providers.</p>
|
|
<p>One of the nice things about DO is that we can upload and store our own custom OS images, which makes life much easier when we want to deploy Alpine-based hosts, for example, and they also offer much more detailed metrics and monitoring than our other hosting providers, which really helps with making sure we've got everything sized correctly and aren't overpaying or underperforming. They do also offer a Container Registry service, but it's designed for private, internal use, and their largest offering is only 100 GB storage, which we would burn through in no time (<a href="https://github.com/linuxserver/docker-webtop">Webtop</a> alone accounts for over 3Tb of images).</p>
|
|
<p>In the 4 years I've been part of Linuxserver I don't think we've had a single outage across our droplets, which is honestly quite impressive, and with weekly backups (<a href="https://www.digitalocean.com/blog/daily-backups-now-generally-available">daily now available</a>) and on-demand snapshots we've got some pretty solid reliability for our services. However, even the best hosting provider can't protect you against someone screwing up while managing a box and so we've taken some additional steps to try and protect ourselves.</p>
|
|
<h3>Monitoring</h3>
|
|
<p>Beyond the metrics and alerting provided by DO, we use <a href="https://github.com/TwiN/gatus">Gatus</a> to monitor our services for outages, and it doubles as a <a href="https://status.linuxserver.io/">public status page</a>. If something goes down we know about it within a few minutes, rather than relying on chance or annoyed users notifying us about it. We also monitor a number of 3rd party services that we rely heavily on, such as the Docker registries and the Github API so that when users complain about not being able to pull images we know if there's a wider issue.</p>
|
|
<h3>Pre-Prod</h3>
|
|
<p>We operate a pre-production clone of our live website that allows us to test upgrades and changes without making us look too stupid when everything breaks. We were "inspired" to set it up after an upgrade to Grav (our CMS) broke our custom CSS, and it's already paid dividends.</p>
|
|
<h3>Version Control</h3>
|
|
<p>Did you know that Docker Compose can pull from a remote git repo? No? I'm not surprised as it's an experimental feature and <em>very</em> lightly documented. In fact <a href="https://www.docker.com/blog/scaling-docker-compose-up/">this blog post</a> was the only official place outside of the Docker git repos that I found reference to it....</p>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:4:{i:0;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:7:"compose";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:12:"digitalocean";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:14:"infrastructure";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:3;a:6:{s:4:"data";s:173:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:55:"Why Can't You Just Implement <Thing I Want>?";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:72:"https://www.linuxserver.io/blog/why-cant-you-just-implement-thing-i-want";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:72:"https://www.linuxserver.io/blog/why-cant-you-just-implement-thing-i-want";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Sat, 15 Jun 2024 15:56:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:3312:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/3/c/8/f/2/3c8f274f3436473d52d12ac304adcddaca4058cd-13029008984ecac8243ddh.jpg" />
|
|
<p>It's a common refrain: "Why can't you just implement this feature that would make my life easier? It's not even that hard, it's just this environment variable or this bit of init logic. There are lots of people just like me who would benefit from it."</p>
|
|
<p><img title="There are dozens of us! Dozens!!" alt="dozens" src="/user/pages/03.blog/why-cant-you-just-implement-thing-i-want/dozens.gif?decoding=auto"></p>
|
|
<p>It should be pretty obvious that we can't implement every feature request we receive, but the important question is why didn't we implement <strong>yours</strong>?</p>
|
|
<h3>KISS</h3>
|
|
<p>As The Notorious B.I.G famously said: Mo Code Mo Problems. Almost every time we add functionality to an image, we're increasing its complexity, and the number of ways it can go wrong. Sure <em>you</em> made this change in your homelab and it's all working fine, but <em>you</em> are not representative of our user base. You're not running on a 3.x kernel, or on a prebuilt NAS that still ships version 17.x of Docker, or on Proxmox running a VM running LXC running Docker in Docker <em>for no good reason</em>. You also probably didn't copy/paste our docker compose example as-is and spin it up; a surprising number of people do, so every extra configuration option requires a level of planning and documentation to ensure that those copy/pasters don't end up with a broken install, which brings us to...</p>
|
|
<h3>Limited Resources</h3>
|
|
<p>We're all volunteers - none of us get paid for this - and we do it in our own time because we enjoy it. Having people yell at you that you're shit because you won't do the things they want is not enjoyable. We have to be realistic about what we're able to support, which is why when images start to require too much ongoing work to keep them running, we have to take a hard look at whether they're worth continuing to maintain (RIP armhf). We maintain over 200 images, so while for you this is a quick fix for your particular use case, for us it could open the gates to a <em>lot</em> of extra work.</p>
|
|
<p>It's impossible for us to provide support for every use case, and every conceivable way of running our images, which is why we have a published <a href="https://www.linuxserver.io/supportpolicy">Support Policy</a> to try and limit the scope of what we're expected to cover. We're not doing it because we hate k8s or Podman, or think running rootless is a bad idea, we're doing it because we have to draw a reasonable support boundary that covers the majority of our users. What this means is that if you come to us and say "I'm using this thing you don't support and I want you to change your images to make my life easier doing it" we're probably going to say no, unless it's something trivial with no risk of impacting anything else.</p>
|
|
<h3>But <em>My</em> Case Is Different</h3>
|
|
<p>We can't be all things to all people. Even if we had unlimited resources it just isn't practical to support <em>everything</em> with one image. We design our images with a particular audience in mind: homelab users running...</p>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:3:{i:0;a:5:{s:4:"data";s:10:"containers";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:11:"linuxserver";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:4;a:6:{s:4:"data";s:347:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:22:"Advanced Wireguard Hub";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:54:"https://www.linuxserver.io/blog/advanced-wireguard-hub";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:54:"https://www.linuxserver.io/blog/advanced-wireguard-hub";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Thu, 16 Nov 2023 11:50:00 +0000";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:4770:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/d/6/d/8/4/d6d84245c3136f50224e55df8ccfe9eab152762e-hub2.png" />
|
|
<p><img title="hub" alt="hub" src="/user/pages/03.blog/advanced-wireguard-hub/hub.png"></p>
|
|
<p>In a couple of prior articles (<a href="https://www.linuxserver.io/blog/routing-docker-host-and-container-traffic-through-wireguard"><strong>here</strong></a> and <a href="https://www.linuxserver.io/blog/advanced-wireguard-container-routing"><strong>here</strong></a>) we showcased the capabilities of <a href="https://github.com/linuxserver/docker-wireguard">our WireGuard Docker container</a> with some real world examples. At the time, our WireGuard container only supported one active tunnel at a time so the second article resorted to using multiple WireGuard containers running on the same host and using the host's routing tables to do advanced routing between and through them.</p>
|
|
<p>In October 2023, our WireGuard container received a <a href="https://github.com/linuxserver/docker-wireguard#versions">major update</a> and started supporting multiple WireGuard tunnels at a time, which made it much more versatile than before. In this article we'll take advantage of this new capability and showcase a setup that involves a single container that acts as both a server and a client that tunnels peers through multiple redundant VPN connections while maintaining access to the LAN.</p>
|
|
<p>Many VPN providers have a limit on the number of devices (or tunnels). This setup will allow you to have an unlimited amount of devices tunneled through a single VPN connection while also supporting a fail-over backup connection!</p>
|
|
<p>DISCLAIMER: This article is not meant to be a step by step guide, but instead a showcase for what can be achieved with our WireGuard image. We do not officially provide support for routing whole or partial traffic through our WireGuard container (aka split tunneling) as it can be very complex and require specific customization to fit your network setup and your VPN provider's. But you can always seek community support on our <a href="https://discord.gg/YWrKVTn">Discord server</a>'s #other-support channel. </p>
|
|
<p>Tested on Ubuntu 23.04, Docker 24.0.5, Docker Compose 2.20.2, with Mullvad.</p>
|
|
<h2>Requirements</h2>
|
|
<ul>
|
|
<li>A working instance of our <a href="https://github.com/linuxserver/docker-wireguard">Wireguard container</a> in server mode.</li>
|
|
</ul>
|
|
<h2>Initial WireGuard Server Configuration</h2>
|
|
<p>Configure a standard WireGuard server according to the <a href="https://github.com/linuxserver/docker-wireguard">WireGuard documentation</a>.</p>
|
|
<pre><code class="language-Yaml"> wireguard:
|
|
image: lscr.io/linuxserver/wireguard:latest
|
|
container_name: wireguard
|
|
cap_add:
|
|
- NET_ADMIN
|
|
- SYS_MODULE
|
|
environment:
|
|
- PUID=1000
|
|
- PGID=1000
|
|
- TZ=Etc/UTC
|
|
- SERVERURL=wireguard.domain.com
|
|
- SERVERPORT=51820
|
|
- PEERS=1
|
|
- PEERDNS=auto
|
|
- INTERNAL_SUBNET=10.13.13.0
|
|
volumes:
|
|
- /path/to/appdata/config:/config
|
|
- /lib/modules:/lib/modules
|
|
ports:
|
|
- 51820:51820/udp
|
|
sysctls:
|
|
- net.ipv4.conf.all.src_valid_mark=1
|
|
restart: unless-stopped</code></pre>
|
|
<p>Start the container and validate that <code>docker logs wireguard</code> contains no errors, and validate that the server is working properly by connecting a client to it.</p>
|
|
<h2>VPN Client Tunnels Configuration</h2>
|
|
<p>Copy the 2 WireGuard configs that you get from your VPN providers into files under <code>/config/wg_confs/wg1.conf</code> and <code>/config/wg_confs/wg2.conf</code>.</p>
|
|
<h3>Example wg1.conf</h3>
|
|
<p>Make the following changes:</p>
|
|
<ul>
|
|
<li>Add <code>Table = 55111</code> to distinguish rules for this interface.</li>
|
|
<li>Add <code>PostUp = ip rule add pref 10001 from 10.13.13.0/24 lookup 55111</code> to forward traffic from the wireguard server through the tunnel using table 55111 and priority 10001.</li>
|
|
<li>Add <code>PreDown = ip rule del from 10.13.13.0/24 lookup 55111</code> to remove the previous rule when the interface goes down.</li>
|
|
<li>Add <code>PersistentKeepalive = 25</code> to keep the tunnel alive.</li>
|
|
<li>Add <code>AllowedIPs =</code> and calculate the value using a <a href="https://www.procustodibus.com/blog/2021/03/wireguard-allowedips-calculator/">Wireguard AllowedIPs Calculator</a>.
|
|
<ul>
|
|
<li>Write <code>0.0.0.0/0</code> in the <code>Allowed IPs</code> field.</li>
|
|
<li>Write your LAN subnet and Wireguard server subnet in the <code>Disallowed IPs</code> field, for example: <code>192.168.0.0/24, 10.13.13.0/24</code>, make sure it doesn't include the VPN interface address (...</li></ul></li></ul>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:9:{i:0;a:5:{s:4:"data";s:5:"linux";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:6:"guides";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:6:"how to";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:3:"vpn";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:9:"wireguard";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:6;a:5:{s:4:"data";s:7:"routing";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:7;a:5:{s:4:"data";s:12:"split tunnel";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:8;a:5:{s:4:"data";s:7:"mullvad";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:5;a:6:{s:4:"data";s:202:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:18:"Our Support Policy";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:50:"https://www.linuxserver.io/blog/our-support-policy";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:50:"https://www.linuxserver.io/blog/our-support-policy";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Thu, 26 Oct 2023 11:00:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:2558:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/6/7/f/1/b/67f1bb22f86142002e43a5ea48edb6a96789e80e-167379978354b8499d246o.jpg" />
|
|
<p>We maintain a lot of images, which are used by a lot of people, on a lot of platforms, using a lot of tools, and it's not always immediately clear which of those many combinations we support, and will provide support for. This post is an attempt to clarify that situation and provide links to our formal documentation on the matter.</p>
|
|
<p>Any exceptions to our support policy will be clearly called out in the readme for the relevant image.</p>
|
|
<p>The TL;DR is if you run up to date versions of our currently maintained images using a supported version of Docker, rootfully, on Linux, using docker compose or the docker CLI to create and update your containers, we will support you with any issues you encounter.</p>
|
|
<p>Our support policy can be grouped into 4 categories:</p>
|
|
<ul>
|
|
<li>Formally Supported</li>
|
|
<li>Reasonable Endeavours Support</li>
|
|
<li>Unsupported</li>
|
|
<li>Unsupported and Known To Be Broken</li>
|
|
</ul>
|
|
<p>With the exception of the last category it's worth noting that unsupported does not mean it won't work, it just means we won't help you make it work. Additionally, if you <em>do</em> manage to get something in the last category working it doesn't change anything, it's still unsupported and a bad idea. Requests for help with anything outside of the Formally Supported category should use the <code>#other-support</code> channel on our <a href="https://discord.gg/linuxserver">Discord</a> server.</p>
|
|
<p>Our general support philosophy can be summarised as follows:</p>
|
|
<ul>
|
|
<li>If we build and test on it, we support you running on it.</li>
|
|
<li>If it's not formally supported but we use it ourselves or we know it works, we'll make reasonable endeavours to help you with issues.</li>
|
|
<li>If we don't have knowledge of, or the ability to test/replicate your configuration, we will not provide support for it (though other community members may still be able to help you).</li>
|
|
<li>If we know a configuration will not work, or has serious issues, we will not provide any support for it and will advise you of the risks.</li>
|
|
</ul>
|
|
<p>With that out of the way, our current support policy can always be found at <a href="https://linuxserver.io/supportpolicy">https://linuxserver.io/supportpolicy</a> and we will make announcements via our usual channels if anything substantial changes.</p>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:4:{i:0;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:11:"linuxserver";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:7:"support";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:6:"policy";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:6;a:6:{s:4:"data";s:231:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:12:"Hello MkDocs";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:44:"https://www.linuxserver.io/blog/hello-mkdocs";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:44:"https://www.linuxserver.io/blog/hello-mkdocs";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Wed, 25 Oct 2023 23:50:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:3224:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/2/b/8/1/7/2b81795e9aee3d9d6c9820513b44cff9528634e8-archive-18501701920.jpg" />
|
|
<p>As early as 2019, we started centralizing all our documentation for container images, informational snippets, Frequently Asked Questions as well as full-blown user-guides, this has all lived on GitBook. The reason for going with GitBook at the time was simply because of its native ability to build off of a git repo, as well as its hosted nature (yes, we want to spend most of our time creating containers, not maintaining infrastructure). We were also considering Read The Docs and Bookstack for this usecase. The git integration was a killer feature, as it allowed us to implement it as step in our <a href="https://www.linuxserver.io/blog/2019-02-21-the-lsio-pipeline-project">pipeline project</a> to automatically push updated documentation with the same base as the readme. </p>
|
|
<p>As time went on, the LinuxServer team grew. Which as an organization, the skillset also grew. A part of this skillset included various takes on other documentation tools. Since we always want improve, our documentation has also seen multiple iterations. While doing these updates certain pain points arose:</p>
|
|
<ul>
|
|
<li>No ability to easily test changes, other tools we knew for documenting let us spin up a development instance.
|
|
<ul>
|
|
<li>This caused multiple pushes to master in order to test i.e. GitBook specific markdown syntax. </li>
|
|
</ul></li>
|
|
<li>No automatic index generation. For some reason the git integration we depend on does not automatically update the index of pages, meaning that while we push a file for a new container image into the repo, it does not get included on the site.
|
|
<ul>
|
|
<li>For 3 years, listing the latest containers in the sidebar was a <a href="https://github.com/linuxserver/docker-documentation/commits/master?before=a75f02127ae30e06001aa32619d908f58dd906ad%2B35&branch=master&path%5B%5D=SUMMARY.md&qualified_name=refs%2Fheads%2Fmaster">manual task</a>, which we automated in <a href="https://github.com/linuxserver/docker-documentation/pull/63">Nov 2022</a>. </li>
|
|
</ul></li>
|
|
<li>GitBook also doesn't build pages for markdown-files that are in the repo, but not defined in the index, which means we couldn't publish documentation for "pre-release" containers, which are applications we package despite there being no stable build upstream. </li>
|
|
</ul>
|
|
<h2>Freezing GitBook</h2>
|
|
<p>The sync from our GitHub repo to GitBook has been disabled for a couple of months, as we have been preparing, improving and testing MkDocs. The freeze has been necessary because we adapted the templates our jenkins-builder generates for MkDocs, and we didn't want the current docs to get formatted weirdly, as the syntaxes differ just enough.</p>
|
|
<p>The switch to MkDocs allows us to customize the build-output to our liking, with the knowledge we have within the team. It also resolves all the pain-points listed above.</p>
|
|
<h3>Thanks GitBook</h3>
|
|
<p>We would just like to give a shout out to GitBook and say thank you for providing us with a OSS license.</p>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:5:{i:0;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:13:"documentation";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:6:"readme";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:6:"mkdocs";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:7:"gitbook";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:7;a:6:{s:4:"data";s:318:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:41:"Docker Tags: So Many Tags, So Little Time";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:71:"https://www.linuxserver.io/blog/docker-tags-so-many-tags-so-little-time";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:71:"https://www.linuxserver.io/blog/docker-tags-so-many-tags-so-little-time";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Mon, 07 Aug 2023 11:31:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:4601:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/9/0/7/f/4/907f4e40abf3476189235d75be300e11b90c3774-angele-kamp-kaeauitiwnc-unsplash.jpg" />
|
|
<p>As an organization, we maintain hundreds of Docker images and with each image having multiple tags and different naming conventions on different registries, things can become confusing. In this article we attempt to untangle that web and clarify how all the images and tags we push relate to each other.</p>
|
|
<h2>Table Of Contents:</h2>
|
|
<ul>
|
|
<li><a href="#nomenclature">Nomenclature</a></li>
|
|
<li><a href="#registries-used-by-linuxserver-io">Registries Used By Linuxserver.io</a>
|
|
<ul>
|
|
<li><a href="#docker-hub-docker-io">Docker Hub (docker.io)</a></li>
|
|
<li><a href="#github-container-registry-ghcr-io">Github Container Registry (ghcr.io)</a></li>
|
|
<li><a href="#quay">Quay</a></li>
|
|
<li><a href="#gitlab">GitLab</a></li>
|
|
<li><a href="#lscr-io-honorable-mention">Lscr.io (Honorable Mention)</a></li>
|
|
</ul></li>
|
|
<li><a href="#branch-tags">Branch Tags</a></li>
|
|
<li><a href="#manifests">Manifests</a>
|
|
<ul>
|
|
<li><a href="#1-branch-tag-dynamic">Branch tag (dynamic)</a></li>
|
|
<li><a href="#2-build-tag-static">Build tag (static)</a></li>
|
|
<li><a href="#3-version-tag-dynamic">Version tag (dynamic)</a></li>
|
|
<li><a href="#4-pseudo-semver-tag-dynamic">Pseudo SemVer tag (dynamic)</a></li>
|
|
</ul></li>
|
|
<li><a href="#dev-and-pr-images-and-tags">Dev and PR Images and Tags</a></li>
|
|
<li><a href="#semver-info">SemVer Info</a></li>
|
|
</ul>
|
|
<h2>Nomenclature</h2>
|
|
<ul>
|
|
<li><strong>Registry:</strong> Docker registry is the location/server where the images are stored. The default registry is <code>docker.io</code>.</li>
|
|
<li><strong>Image tag:</strong> Each docker image is assigned a specific tag. If no tag is defined when pushing or pulling, the default tag <code>latest</code> is used. The format is <code><registry>/<repo>/<image>:<tag></code> (except for Gitlab, which uses the format <code><registry>/organization/<repo>/<image>:<tag></code>). If <code><registry></code> is not provided, it defaults to <code>docker.io</code>, so attempting to pull <code>linuxserver/swag</code> will result in pulling <code>docker.io/linuxserver/swag:latest</code>.</li>
|
|
<li><strong>Manifest:</strong> Docker image manifest contains information on the size, layers and digest of an image. A manifest can also contain a list of these items for multiple images such as a multi-arch image manifest. When issuing a <code>docker pull</code>, the image manifest is first retrieved.</li>
|
|
<li><strong>Dynamic tag:</strong> If a docker image tag is updated or overwritten by newer images over time, it is considered a dynamic image tag. Pulling that tag at different times may result in pulling different images. <code>lscr.io/linuxserver/swag:latest</code> tag is a dynamic one and it points to a different image every time a new stable build is pushed. Static tags on the other hand are pushed to the registry once and never updated. Repulling the same static tag at a later time will pull the same image as before. <code>lscr.io/linuxserver/swag:arm64v8-2.6.0-ls224</code> is a static tag as it contains the specific build number (<code>ls224</code>) and will not get overwritten as the build number will get incremented in the next build and push.</li>
|
|
</ul>
|
|
<h2>Registries Used By Linuxserver.io</h2>
|
|
<p>We push our images to four public registries. There are subtle differences between these registries in how the repos and images are structured and named.</p>
|
|
<h3>Docker Hub (docker.io)</h3>
|
|
<p>Docker.io is the default registry. If the user does not define a registry in a command, docker client automatically adds <code>docker.io/</code>. For instance pulling <code>linuxserver/swag</code> is the same as pulling <code>docker.io/linuxserver/swag</code></p>
|
|
<p>In the beginning of time, Linuxserver.io decided to set up multiple organizations on Docker Hub to host images. There were separate orgs for different arches such as <code>armhf</code> and <code>aarch64</code>, and there were separate orgs for baseimages and community images. Over time, the secondary arch images were brought under the same orgs as the <code>amd64</code> ones through the use of multi-arch manifests and those additional orgs were deprecated. The community org that hosted community provided and maintained images was also deprecated as we realized that the community did not contribute further into support and maintenance of the images,...</p>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:8:{i:0;a:5:{s:4:"data";s:5:"linux";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:3:"tag";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:5:"image";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:8:"registry";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:4:"GHCR";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:6;a:5:{s:4:"data";s:4:"quay";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:7;a:5:{s:4:"data";s:6:"gitlab";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:8;a:6:{s:4:"data";s:463:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:42:"Webtop 2.0 - The year of the Linux desktop";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:72:"https://www.linuxserver.io/blog/webtop-2-0-the-year-of-the-linux-desktop";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:72:"https://www.linuxserver.io/blog/webtop-2-0-the-year-of-the-linux-desktop";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Fri, 21 Jul 2023 19:40:48 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:4077:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/4/d/4/3/6/4d43690adcf68700937e797299fc38bf63fa92f4-registry.png" />
|
|
<p>It has been two years since <a href="https://github.com/linuxserver/docker-webtop">Webtop</a> and our accompanying base images were released with the goal of delivering a full Linux Desktop to your Web Browser.
|
|
If you were not aware the backend technology enabling this was a combination of <a href="https://github.com/neutrinolabs/xrdp">xrdp</a>, <a href="https://guacamole.apache.org/">Guacamole</a>, and an in house client <a href="https://github.com/linuxserver/gclient">Gclient</a>. Guacamole and xrdp are amazing pieces of software, but are held back by forcing a square peg into a round hole. Most remote desktop software is built for a native desktop client and requires a significant amount of overhead to convert it into a format a modern Web browser understands, because of that fidelity and performance is not great. The folks at <a href="https://novnc.com/info.html">noVNC</a> have done a great job of creating an RFB compliant native VNC client for the browser, but again they are bound by that protocol and can only do so much to optimize for web. </p>
|
|
<p>This led me (TheLamer) down a rabbit hole of trying to find an open source project with the singular goal of delivering Linux to Web Browsers. I am happy to announce, after more than a year of work in the background, that not only have I found it but have joined the <a href="https://www.kasmweb.com/kasmvnc">KasmVNC</a> team to see this through. This is the fundamental technology driving the new containers that just went live. Some important notes before we get started: </p>
|
|
<ul>
|
|
<li><strong>Armhf is being deprecated, it has simply become too difficult to continue to support the porting of everything that makes up desktop environments and the accompanying applications. Almost every single board computer supports aarch64 at this point, so please take the time to install an arm64 OS, it will be worth it.</strong></li>
|
|
<li><strong>For best results use a Chromium based browser. Firefox works, but their rendering engine and WebAssembly integration is simply not as fast.</strong></li>
|
|
</ul>
|
|
<h2>We are approaching reality</h2>
|
|
<p>Here is a quick comparison of our previous version vs now: (1080p capture)</p>
|
|
<p><video controls="controls" title="fidelity" alt="fidelity"><source src="/user/pages/03.blog/webtop-2-0-the-year-of-the-linux-desktop/fidelity.mp4?loading=auto&decoding=auto">Your browser does not support the video tag.</source></video></p>
|
|
<p>On top of a drastic improvement in responsiveness and FPS there is also fidelity with fine grain control over compression, format, and frame-rate to suit your needs.<br>
|
|
The real question though is how high can you go?<br>
|
|
<img title="all-go-to-11" alt="all-go-to-11" src="/user/pages/03.blog/webtop-2-0-the-year-of-the-linux-desktop/all-go-to-11.gif?decoding=auto"><br>
|
|
Lossless, not fake lossless, or semi lossless, but actual true 24 bit RGB leveraging the <a href="https://qoiformat.org/">Quite OK Image Format</a> decoded client-side with threaded webassembly, more info <a href="https://www.kasmweb.com/docs/latest/how_to/lossless.html">here</a>. Even better this mode is capable of going over a gigabit at high FPS so if you have been eyeballing that 10gb switch you just found your excuse.<br>
|
|
When you pair this with the 32-bit float audio and a fullscreen browser window you get that local feel all from the comfort of your browser. </p>
|
|
<p>It is difficult to show a demo of what lossless is like so why not try it yourself? </p>
|
|
<pre><code>sudo docker run --rm -it --security-opt seccomp=unconfined --shm-size="1gb" -p 3001:3001 lscr.io/linuxserver/webtop:latest bash</code></pre>
|
|
<p>Hop into https://yourhost:3001 and swap <strong>Settings > Stream Quality > Preset Modes > Lossless</strong>. Check <strong>Render Native Resolution</strong> if you use UI scaling.</p>
|
|
<h2>New</h2>...
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:13:{i:0;a:5:{s:4:"data";s:6:"ubuntu";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:3:"VDI";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:4:"XFCE";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:3:"KDE";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:6:"Alpine";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:6;a:5:{s:4:"data";s:4:"MATE";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:7;a:5:{s:4:"data";s:10:"Arch Linux";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:8;a:5:{s:4:"data";s:6:"Debian";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:9;a:5:{s:4:"data";s:6:"Webtop";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:10;a:5:{s:4:"data";s:7:"KasmVNC";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:11;a:5:{s:4:"data";s:6:"Fedora";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:12;a:5:{s:4:"data";s:14:"Remote Desktop";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:9;a:6:{s:4:"data";s:260:"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:6:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:21:"A Farewell To Arm(hf)";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:52:"https://www.linuxserver.io/blog/a-farewell-to-arm-hf";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:52:"https://www.linuxserver.io/blog/a-farewell-to-arm-hf";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"Thu, 06 Apr 2023 12:00:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:3239:"
|
|
|
|
<img alt="" src="https://www.linuxserver.io/images/5/3/e/f/5/53ef5f81117e764bc6d2279f2b2e19ed2ea17fd7-banner-armhf.png" />
|
|
<h3>The State of Play</h3>
|
|
<p>As we wrote <a href="https://www.linuxserver.io/blog/end-of-an-arch">almost a year ago now</a>, 32-bit Arm has been on life support for a while, and you may have noticed that none of the new images we've released in recent months have offered 32-bit Arm (armhf) versions, and a number of older images have dropped support over the same period. This has been part of our "soft deprecation" of the architecture, as it has become more and more difficult to support with contemporary applications.</p>
|
|
<p>Last week, Raspberry Pi OS <a href="https://github.com/raspberrypi/linux/issues/5402">started defaulting to a 64-bit kernel on boot</a>, if the hardware supports it, which was possibly not the most graceful way to handle things, but here we are. What this means is that, essentially, 32-bit Arm has transitioned from "on life support" to "doomed"; there is obviously still hardware out there that doesn't support 64-bit, but the single biggest pool of users who <em>can</em> move to 64-bit is now having it (sort of) done for them.</p>
|
|
<h3>What Now?</h3>
|
|
<p>A year ago, around 2/3 of our Arm users were still on 32-bit platforms, today it's less than 1/5, and consequently we have taken the difficult decision to formally deprecate 32-bit Arm builds from 2023-07-01. Due to the number of images and how our build pipelines work there's going to be some wiggle room here, but essentially from the 1st of July 2023 we will no longer support any 32-bit platforms.</p>
|
|
<p>Old images will continue to work, but will not receive application or OS updates, and we will not provide support for them. Additionally, the <code>latest</code> and <code>arm32v7-latest</code> tags will no longer work for 32-bit Arm, you will need to provide a specific version tag if you wish to pull one of the old images.</p>
|
|
<p>If you're currently using our 32-bit Arm images, what are your options?</p>
|
|
<ul>
|
|
<li>If you're not sure what architecture you're on, run <code>uname -m</code> from a terminal session - a response of <code>armv7l</code> or <code>armhf</code> means you're running a 32-bit kernel.</li>
|
|
<li>You may also have a 64-bit kernel with a 32-bit userspace, especially if you're running an OS like LibreELEC or OSMC, which likely means a 32-bit Docker install. Running <code>getconf LONG_BIT</code> will give you a response of <code>32</code> if this is the case.</li>
|
|
<li>If your hardware is Armv8 and offers support for 64-bit, such as the Pi 3 or 4, or Zero 2 W, then look to migrate to a 64-bit OS.</li>
|
|
<li>If your hardware is Armv7 or Armv6 you don't have a lot of options other than replacing it or accepting the risk and inconvenience of remaining on old versions of the images, the hardware simply doesn't support 64-bit.</li>
|
|
</ul>
|
|
<p>As before, we know this probably isn't what you want to hear, but unfortunately technology marches forward and 32-bit is doomed. Hopefully by providing as much notice as possible you'll have time to find a solution that works for you.</p>
|
|
|
|
";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:6:{i:0;a:5:{s:4:"data";s:5:"linux";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:6:"docker";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:5:"armhf";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:12:"announcement";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:11:"deprecation";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:3:"arm";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}}}s:27:"http://www.w3.org/2005/Atom";a:1:{s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:0:"";s:7:"attribs";a:1:{s:0:"";a:3:{s:4:"href";s:35:"https://www.linuxserver.io/blog.rss";s:3:"rel";s:4:"self";s:4:"type";s:19:"application/rss+xml";}}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}}}}}}}}s:4:"type";i:128;s:7:"headers";a:10:{s:6:"server";s:5:"nginx";s:4:"date";s:29:"Mon, 16 Dec 2024 21:44:34 GMT";s:12:"content-type";s:34:"application/rss+xml; charset=utf-8";s:10:"connection";s:10:"keep-alive";s:12:"x-powered-by";s:10:"PHP/8.3.13";s:10:"set-cookie";s:195:"linux-server-io-b4e2fbe59292f23ee327e4043b64b395=psutna32p255312hcb5cpi6co8; expires=Mon, 16 Dec 2024 22:14:34 GMT; Max-Age=1800; path=/; domain=www.linuxserver.io; secure; HttpOnly; SameSite=Lax";s:6:"pragma";s:8:"no-cache";s:13:"cache-control";s:14:"max-age=604800";s:7:"expires";s:29:"Mon, 23 Dec 2024 21:44:34 GMT";s:4:"etag";s:34:""d9cbdd56873a302ace6adc43c4f2ebe3"";}s:5:"build";s:14:"20240924100504";s:5:"mtime";i:1734385474;s:3:"md5";s:32:"a0b341c9ef194e1ef1e795ad7a75ba36";} |