Top Related Projects
s6 overlay for containers (includes execline, s6-linux-utils & a custom init)
A minimal Ubuntu base image modified for Docker-friendliness
Bitnami container images
Various Dockerfiles I use on the desktop and on servers.
Alpine Linux Docker image. Win at minimalism!
Quick Overview
The linuxserver/docker-mods repository is a collection of mods for LinuxServer.io Docker images. These mods allow users to extend the functionality of base images without rebuilding them, providing a flexible way to customize containers. The project aims to simplify the process of adding features or tools to existing Docker images.
Pros
- Enhances flexibility of LinuxServer.io Docker images without rebuilding
- Simplifies the process of adding custom functionality to containers
- Promotes community contributions and sharing of useful modifications
- Reduces the need for maintaining separate, customized Docker images
Cons
- May introduce potential security risks if mods are not properly vetted
- Can increase complexity in container management and troubleshooting
- Might lead to inconsistencies across different environments if not carefully managed
- Limited to LinuxServer.io images, not applicable to all Docker containers
Getting Started
To use a docker mod with a LinuxServer.io image, follow these steps:
- Choose a compatible LinuxServer.io image
- Set the
DOCKER_MODS
environment variable when running the container - Specify the desired mod using the format:
linuxserver/mods:imagename-modname
Example:
docker run -d \
--name=plex \
-e PUID=1000 \
-e PGID=1000 \
-e VERSION=docker \
-e DOCKER_MODS=linuxserver/mods:plex-mod_name \
-p 32400:32400 \
-v /path/to/library:/config \
-v /path/to/tvseries:/tv \
-v /path/to/movies:/movies \
--restart unless-stopped \
linuxserver/plex
Replace mod_name
with the specific mod you want to use. You can chain multiple mods by separating them with |
, like this: DOCKER_MODS=linuxserver/mods:plex-mod1|linuxserver/mods:plex-mod2
For more information and available mods, visit the linuxserver/docker-mods repository on GitHub.
Competitor Comparisons
s6 overlay for containers (includes execline, s6-linux-utils & a custom init)
Pros of s6-overlay
- More comprehensive init system with process supervision
- Better suited for complex multi-process containers
- Provides a standardized way to manage services and logging
Cons of s6-overlay
- Steeper learning curve for newcomers
- Requires more setup and configuration
- May be overkill for simple, single-process containers
Code Comparison
s6-overlay example:
#!/usr/bin/with-contenv bash
exec /usr/bin/myapp
docker-mods example:
#!/bin/bash
/usr/bin/myapp
Key Differences
s6-overlay focuses on providing a complete init and process supervision system for containers, while docker-mods is primarily designed for modifying existing LinuxServer.io images with additional functionality.
s6-overlay offers more robust process management and service orchestration, making it suitable for complex container setups. docker-mods, on the other hand, provides a simpler approach to extending container functionality, particularly within the LinuxServer.io ecosystem.
The choice between the two depends on the specific requirements of your container setup and your familiarity with each system. s6-overlay is more powerful but requires more knowledge, while docker-mods is easier to use but may be limited in some scenarios.
A minimal Ubuntu base image modified for Docker-friendliness
Pros of baseimage-docker
- Provides a comprehensive base image with init system and process management
- Includes useful utilities and optimizations for containerized environments
- Well-documented and maintained by a dedicated team
Cons of baseimage-docker
- Larger image size due to included components
- May include unnecessary features for simpler applications
- Less flexibility in customizing the base environment
Code Comparison
baseimage-docker:
FROM phusion/baseimage:focal-1.1.0
RUN /sbin/my_init
CMD ["/sbin/my_init"]
docker-mods:
FROM alpine:3.14
RUN apk add --no-cache bash
COPY root/ /
Key Differences
docker-mods focuses on providing a lightweight and flexible approach to extending Docker images, allowing users to add specific functionality to existing containers. It's designed for modularity and easy integration with LinuxServer.io images.
baseimage-docker, on the other hand, offers a more comprehensive solution with a pre-configured environment suitable for running multiple processes and services within a single container. It's ideal for complex applications that require a more traditional system-like setup.
While docker-mods emphasizes simplicity and customization, baseimage-docker prioritizes robustness and out-of-the-box functionality. The choice between them depends on the specific requirements of your containerized application and your preferred approach to container management.
Bitnami container images
Pros of containers
- Wider range of applications and services covered
- More frequent updates and maintenance
- Comprehensive documentation and usage guides
Cons of containers
- Larger image sizes due to more comprehensive packages
- Less flexibility for customization compared to docker-mods
- Steeper learning curve for beginners
Code comparison
docker-mods:
FROM ghcr.io/linuxserver/baseimage-ubuntu:focal
RUN \
echo "**** install packages ****" && \
apt-get update && \
apt-get install -y \
package1 \
package2
containers:
FROM docker.io/bitnami/minideb:bullseye
RUN install_packages package1 package2
COPY rootfs /
ENTRYPOINT [ "/opt/bitnami/scripts/app/entrypoint.sh" ]
CMD [ "/opt/bitnami/scripts/app/run.sh" ]
The docker-mods approach focuses on simplicity and flexibility, allowing users to easily add modifications to existing images. containers, on the other hand, provides more comprehensive and production-ready images with built-in scripts and configurations.
Both repositories serve different purposes and cater to different user needs. docker-mods is ideal for users who want to customize existing images, while containers is better suited for those seeking ready-to-use, well-maintained application images.
Various Dockerfiles I use on the desktop and on servers.
Pros of dockerfiles
- Extensive collection of Dockerfiles for various applications and tools
- Well-maintained and regularly updated
- Includes Dockerfiles for desktop applications and GUI tools
Cons of dockerfiles
- Focuses primarily on individual Dockerfiles rather than modular additions
- May require more manual configuration for complex setups
- Less emphasis on community-driven contributions and modifications
Code Comparison
dockerfiles:
FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y \
firefox-esr \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "firefox" ]
docker-mods:
FROM ghcr.io/linuxserver/baseimage-ubuntu:jammy
RUN \
echo "**** install packages ****" && \
apt-get update && \
apt-get install -y \
firefox-esr && \
echo "**** clean up ****" && \
apt-get clean && \
rm -rf \
/tmp/* \
/var/lib/apt/lists/* \
/var/tmp/*
# add local files
COPY root/ /
The dockerfiles project provides a straightforward Dockerfile for Firefox, while docker-mods offers a more structured approach with additional cleanup steps and the ability to include local files. docker-mods also uses a base image from the LinuxServer.io ecosystem, which may provide additional benefits for users of their containers.
Alpine Linux Docker image. Win at minimalism!
Pros of docker-alpine
- Extremely lightweight base image, resulting in smaller container sizes
- Optimized for Docker environments, with minimal dependencies
- Provides a clean slate for building custom images
Cons of docker-alpine
- Limited package availability compared to full-featured distributions
- May require additional configuration for complex applications
- Steeper learning curve for users unfamiliar with Alpine Linux
Code Comparison
docker-alpine:
FROM alpine:3.14
RUN apk add --no-cache python3 py3-pip
COPY requirements.txt .
RUN pip3 install -r requirements.txt
CMD ["python3", "app.py"]
docker-mods:
FROM ghcr.io/linuxserver/baseimage-ubuntu:focal
RUN apt-get update && apt-get install -y python3 python3-pip
COPY requirements.txt .
RUN pip3 install -r requirements.txt
CMD ["python3", "app.py"]
The docker-alpine example uses Alpine Linux as the base image and the apk
package manager, resulting in a smaller image size. The docker-mods example uses Ubuntu as the base image and the apt-get
package manager, providing a more familiar environment for many users but with a larger image size.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Intro
The purpose of the repository is to provide examples and guidance in creating and storing a user consumable modification layer for the Library of Linuxserver.io Containers. At its core a Docker Mod is a tarball of files stored on Dockerhub and/or GitHub Container Registry that is downloaded and extracted on container boot before any init logic is run. This allows:
- Developers and community users to modify base containers to suit their needs without the need to maintain a fork of the main docker repository
- Mods to be shared with the Linuxserver.io userbase as individual independent projects with their own support channels and development ideologies
- Zero cost hosting and build pipelines for these modifications leveraging GitHub Container Registry and Dockerhub
- Full custom configuration management layers for hooking containers into each other using environment variables contained in a compose file
It is important to note to end users of this system that there are not only extreme security implications to consuming files from sources outside of our control, but by leveraging community Mods you essentially lose direct support from the core LinuxServer team. Our first and foremost troubleshooting step will be to remove the DOCKER_MODS
environment variable when running into issues and replace the container with a clean LSIO one.
Again, when pulling in logic from external sources practice caution and trust the sources/community you get them from.
LinuxServer.io Hosted Mods
We host and publish official Mods at the linuxserver/mods endpoint as separate tags. Each tag is in the format of <imagename>-<modname>
for the latest versions, and <imagename>-<modname>-<commitsha>
for the specific versions.
Here's a list of the official Mods we host: https://mods.linuxserver.io/
Using a Docker Mod
Before consuming a Docker Mod ensure that the source code for it is publicly posted along with its build pipeline pushing to Dockerhub.
Consumption of a Docker Mod is intended to be as user friendly as possible and can be achieved with the following environment variables being passed to the container:
- DOCKER_MODS- This can be a single endpoint
user/endpoint:tag
or an array of endpoints separated by|
user/endpoint:tag|user2/endpoint2:tag
- RUN_BANNED_MODS- If this is set to any value you will bypass our centralized filter of banned Dockerhub users and run Mods regardless of a ban
Full example:
docker run
docker create \
--name=nzbget \
-e DOCKER_MODS=lscr.io/linuxserver/mods:universal-tshoot \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=Europe/London \
-p 6789:6789 \
-v /path/to/nzbget/data:/config \
-v /path/to/downloads:/downloads \
--restart unless-stopped \
lscr.io/linuxserver/nzbget
docker compose
---
services:
nzbget:
image: lscr.io/linuxserver/nzbget:latest
container_name: nzbget
environment:
- DOCKER_MODS=lscr.io/linuxserver/mods:universal-tshoot
- PUID=1000
- PGID=1000
- TZ=Europe/London
volumes:
- /path/to/nzbget/data:/config
- /path/to/downloads:/downloads #optional
ports:
- 6789:6789
restart: unless-stopped
This will spin up an nzbget container and apply the custom logic found in the following repository:
https://github.com/linuxserver/docker-mods/tree/universal-tshoot
This mod installs some basic troubleshooting tools such as dig, netstat, nslookup, etc.
Creating and maintaining a Docker Mod
All of the example files referenced in this section are available in the template branch of this repo.
We will always recommend to our users consuming Mods that they leverage ones from active community members or projects so transparency is key here. We understand that image layers can be pushed on the back end behind these pipelines, but every little bit helps. In this repository we will be going over two basic methods of making a Mod along with an example of the GitHub Actions build logic to get this into a Dockerhub and/or GitHub Container Registry endpoint. Though we are not officially endorsing GitHub Actions here it is built in to GitHub repositories and forks making it very easy to get started. If you prefer others feel free to use them as long as build jobs are transparent.
Note One of the core ideas to remember when creating a Mod is that it can only contain a single image layer, the examples below will show you how to add files standardly and how to run complex logic to assemble the files in a build layer to copy them over into this single layer.
Mod Types
We now only support s6 v3 mods. All currently supported Linuxserver base images are using s6 v3, however, older pinned images, forked versions, etc. may still be using v2. New mods will not work with older s6 v2 based images.
Docker Mod Simple - just add scripts
In this repository you will find the Dockerfile
containing:
FROM scratch
# copy local files
COPY root/ /
For most users this will suffice and anything in the root/ folder of the repository will be added to the end users Docker container / path.
New (v3) mods
The most common paths to leverage for Linuxserver images are as follows. Assuming a mod name of universal-mymod
:
.
âââ root
âââ defaults -- Any default config files you need to copy as part of the mod can be placed here
âââ etc
âââ s6-overlay
âââ s6-rc.d
âââ init-mods-end
â âââ dependencies.d
â âââ init-mod-universal-mymod -- If your mod does not need to install packages it should be a dependency of init-mods-end (empty file)
âââ init-mods-package-install
â âââ dependencies.d
â âââ init-mod-universal-mymod -- If your mod needs to install packages it should be a dependency of init-mods-package-install (empty file)
âââ init-mod-universal-mymod
â âââ dependencies.d
â â âââ init-mods -- Tells our init logic that this depends on the `init-mods` step (empty file)
â âââ run -- This is the init logic script that runs before the services in the container. Use `chmod +x` to set proper permissions.
â âââ type -- This should contain the string `oneshot`.
â âââ up -- This should contain the absolute path to `run` e.g. `/etc/s6-overlay/s6-rc.d/init-mod-universal-mymod/run`.
âââ svc-mod-universal-mymod
â âââ dependencies.d
â â âââ init-services -- Tells our init logic that this depends on the `init-services` step (empty file)
â âââ run -- This is the script that runs in the foreground for persistent services. Use `chmod +x` to set proper permissions.
â âââ type -- This should contain the string `longrun`.
âââ user
âââ contents.d
âââ init-mod-universal-mymod -- Tells our init logic that we need this directory (empty file)
âââ svc-mod-universal-mymod -- Tells our init logic that we need this directory (empty file)
Note For
oneshot
scripts you can alternatively omit therun
file entirely and use the execlineb syntax inup
if your requirements are simple enough.
Installing Packages
v3 mods make use of a single package install process for all mods to minimise the amount of calls to external endpoints and speed up the mod init process. If you need to install repo packages you should append them to /mod-repo-packages-to-install.list
for repo packages or /mod-pip-packages-to-install.list
for pip packages and the mod handler will install them for you. Make sure to handle both Ubuntu and Alpine package names if your mod needs to support both e.g.
#!/usr/bin/with-contenv bash
## Ubuntu
if [ -f /usr/bin/apt ]; then
echo "\
dnsutils \
net-tools \
iputils-ping \
traceroute" >> /mod-repo-packages-to-install.list
fi
# Alpine
if [ -f /sbin/apk ]; then
echo "\
bind-tools \
net-tools" >> /mod-repo-packages-to-install.list
fi
If your mod needs to take additional config steps after the packages have been installed, add a second oneshot
script and make it depend on init-mods-package-install
, add it as a dependency of init-mods-end
, and add it to the content bundle e.g.
.
âââ root
âââ etc
âââ s6-overlay
âââ s6-rc.d
âââ init-mods-end
â âââ dependencies.d
â âââ init-mod-universal-mymod-postinstall
âââ init-mod-universal-mymod-postinstall
â âââ dependencies.d
â â âââ init-mods-package-install
â âââ run
â âââ type
â âââ up
âââ user
âââ contents.d
âââ init-mod-universal-mymod-postinstall
Services will always run last, controlled by their dependency on init-services
.
Docker Mod Complex - Sky is the limit
In this repository you will find the Dockerfile.complex
containing:
## Buildstage ##
FROM ghcr.io/linuxserver/baseimage-alpine:3.20 as buildstage
RUN \
echo "**** install packages ****" && \
apk add --no-cache \
curl && \
echo "**** grab rclone ****" && \
mkdir -p /root-layer && \
curl -o \
/root-layer/rclone.deb -L \
"https://downloads.rclone.org/v1.47.0/rclone-v1.47.0-linux-amd64.deb"
# copy local files
COPY root/ /root-layer/
## Single layer deployed image ##
FROM scratch
# Add files from buildstage
COPY --from=buildstage /root-layer/ /
Here we are leveraging a multi stage DockerFile to run custom logic and pull down an rclone deb from the Internet to include in our image layer for distribution. Any amount of logic can be run in this build stage or even multiple build stages as long as the files in the end are combined into a single folder for the COPY command in the final output.
Getting a Mod to Dockerhub
To publish a Mod to DockerHub you will need the following accounts:
- Github- https://github.com/join
- DockerHub- https://hub.docker.com/signup
We recommend using this repository as a template for your first Mod, so in this section we assume the code is finished and we will only concentrate on plugging into GitHub Actions/Dockerhub.
The only code change you need to make to the build logic file .github/workflows/BuildImage.yml
will be to modify the ENDPOINT to your own image:
ENDPOINT: "user/endpoint"
BRANCH: "master"
User is your Dockerhub user and endpoint is your own custom name (typically the name of the repository where your mod is). You do not need to create this endpoint beforehand, the build logic will push it and create it on first run.
Head over to https://github.com/user/endpoint/settings/secrets
and click on New secret
Add DOCKERUSER
(your DockerHub username) and DOCKERPASS
(your DockerHub password or token).
You can create a token by visiting https://hub.docker.com/settings/security
GitHub Actions will trigger a build off of your repo when you commit. The image will be pushed to Dockerhub on success. This Dockerhub endpoint is the Mod variable you can use to customize your container now.
Getting a Mod to GitHub Container Registry
To publish a Mod to GitHub Container Registry you will need the following accounts:
- Github- https://github.com/join
We recommend using this repository as a template for your first Mod, so in this section we assume the code is finished and we will only concentrate on plugging into GitHub Actions/GitHub Container Registry.
The only code change you need to make to the build logic file .github/workflows/BuildImage.yml
will be to modify the ENDPOINT to your own image:
ENDPOINT: "user/endpoint"
BRANCH: "master"
user
is your GitHub user and endpoint
is your own custom name (typically the name of the repository where your mod is). You do not need to create this endpoint beforehand, the build logic will push it and create it on first run.
Head over to https://github.com/<user>/<endpoint>/settings/secrets
and click on New secret
Add CR_USER
(your GitHub username) and CR_PAT
(a personal access token with read:packages
and write:packages
scopes).
You can create a personal access token by visiting https://github.com/settings/tokens
GitHub Actions will trigger a build off of your repo when you commit. The image will be pushed to GitHub Container Registry on success. This GitHub Container Registry endpoint is the Mod variable you can use to customize your container now.
Submitting a PR for a Mod to be added to the official LinuxServer.io repo
- Fork this repo, checkout the
template
branch. - Edit the
Dockerfile
for the mod.Dockerfile.complex
is only an example and included for reference; it should be deleted when done. - Inspect the
root
folder contents. Edit, add and remove as necessary. - After all init scripts and services are created, run
find ./ -path "./.git" -prune -o ( -name "run" -o -name "finish" -o -name "check" ) -not -perm -u=x,g=x,o=x -print -exec chmod +x {} +
to fix permissions. - Edit the readme with pertinent info.
- Finally edit the
.github/workflows/BuildImage.yml
. Customize the vars forBASEIMAGE
andMODNAME
. Set the versioning logic andMULTI_ARCH
if needed. - Ask the team to create a new branch named
<baseimagename>-<modname>
in this repo. Baseimage should be the name of the image the mod will be applied to. The new branch will be based on the template branch. - Submit PR against the branch created by the team.
- Make sure that the commits in the PR are squashed.
- Also make sure that the commit and PR titles are in the format of
<imagename>: <modname> <very brief description like "initial release" or "update">
. Detailed description and further info should be provided in the body (ie.code-server: python2 add python-pip
).
Appendix
File encoding
s6 init files must be encoded in plain UTF-8
, and not UTF-8 with BOM
. You can remove the BOM using your IDE if necessary.
Inspecting mods
To inspect the file contents of external Mods dive is a great CLI tool:
https://github.com/wagoodman/dive
Basic usage:
With Docker
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest <Image Name>
Without Docker
dive <Image Name>
Top Related Projects
s6 overlay for containers (includes execline, s6-linux-utils & a custom init)
A minimal Ubuntu base image modified for Docker-friendliness
Bitnami container images
Various Dockerfiles I use on the desktop and on servers.
Alpine Linux Docker image. Win at minimalism!
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot