22 Commits
Author SHA1 Message Date
Djeex 3529834d95 Fixed deprecated path in qbittorent.md 2026-08-25 10:30:54 +00:00
Djeex fd21bd2f83 feat: add canonical URL and og:url
Docus doesn't generate canonical links or og:url natively. A plugin
now injects rel=canonical and og:url per route using nuxt-site-config's
withSiteUrl, which reads site.url from nuxt.config.ts.
2026-08-11 23:10:26 +02:00
Djeex 2c28b27e82 Fixed darkreader lock 2026-08-11 10:12:54 +00:00
Djeex d22711484b feat: add SEO descriptions to all pages and fix canonical URL 2026-08-11 08:48:59 +00:00
Djeex bfdef4c47a feat: add sitemap generation 2026-08-11 08:32:13 +00:00
Djeex 6129fd31d1 Fixed text 2026-08-03 16:04:44 +00:00
Djeex d839908521 Instameex 2026-08-03 15:52:04 +00:00
Djeex c640801e23 Fixed ")" 2026-03-11 12:06:58 +00:00
Djeex 9e3f116f55 Fixed qbittorrent screenshot 2026-03-11 12:05:05 +00:00
Djeex a59c6c7d4a Fixed Debian version 2026-03-11 11:51:12 +00:00
Djeex 7f0c36fddf Fixed :
- speedtest-tracker typo
- uptime-kuma version
- debian installation dead link
- debian version
- removing ufw from default utilities (too much issues for beginners)
- watchtower fork
- authentik cd + version
- Qbittorent -> Gluetun version
2026-03-11 11:48:28 +00:00
Djeex 3e421f5478 Modified qbit/gluetun max ram + libtorrentv1 2025-10-27 16:35:00 +00:00
Djeex ad86a1f3ce Fixed typo 2025-10-26 18:05:45 +00:00
Djeex d2b6fbec5e Wireguard-15 2025-10-26 17:59:42 +00:00
Djeex a53a424399 Fixed issues 2025-10-22 15:57:05 +00:00
Djeex 77b87485b0 Backrest Dcoker Stop 2025-10-22 15:45:27 +00:00
Djeex a63454ed53 The ProloNAS 2025-10-09 16:35:31 +00:00
Djeex 104efa534c Socat Proxy 2025-10-05 17:08:56 +00:00
Djeex eaabf7db68 hotdisk 2025-10-05 17:03:58 +00:00
Djeex c1f6cff105 Fixed typo 2025-09-02 06:37:46 +00:00
Djeex 5d872ab3c6 Fixed bazarr compose 2025-08-28 20:46:27 +00:00
Djeex 8cfc044087 Lumeex update 2025-08-28 20:41:58 +00:00
57 changed files with 11229 additions and 2914 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ export default defineAppConfig({
docus: { docus: {
title: 'Docudjeex', title: 'Docudjeex',
description: 'Homelab documentation', description: 'Homelab documentation',
url: 'http://docus.dev', url: 'https://docu.djeex.fr',
image: '/img/social.png', image: '/img/social.png',
socials: { socials: {
github:'', github:'',
+1
View File
@@ -1,5 +1,6 @@
--- ---
title: Home title: Home
description: Homelab documentation by Djeex — self-hosting guides for Debian, Docker, networking, storage, and more.
navigation: false navigation: false
layout: page layout: page
main: main:
+2 -1
View File
@@ -1,6 +1,7 @@
--- ---
icon: lucide:home icon: lucide:home
title: Welcome title: Welcome
description: Introduction to Docudjeex — a personal homelab documentation site covering self-hosted services, Debian, and Docker infrastructure.
main: main:
fluid: false fluid: false
--- ---
@@ -9,7 +10,7 @@ main:
# docu[·]{style="color: #1ad6ff"}what? # docu[·]{style="color: #1ad6ff"}what?
__Docu[·]{style="color: #1ad6ff"}djeex__ is a site containing the documentation of my personal servers, originally created to easily keep track of my configurations and commands. __Docu[·]{style="color: #1ad6ff"}djeex__ is a site containing the documentation of my personal servers, originally created to easily keep track of my configurations and commands.
My infrastructure is built around the Debian 12 + Docker combo, making exporting and deployment simpler. My infrastructure is built around the Debian 13 + Docker combo, making exporting and deployment simpler.
Special thanks to __Nipah__, __Xenio__, and others for their patience and support. Most of this content comes directly from them. Special thanks to __Nipah__, __Xenio__, and others for their patience and support. Most of this content comes directly from them.
## About the documentation ## About the documentation
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: NAT & DHCP title: NAT & DHCP
description: Learn how NAT, port forwarding, and DHCP work on a home router. Configure fixed IP leases and understand how to expose local services.
main: main:
fluid: false fluid: false
--- ---
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: DNS Zone title: DNS Zone
description: Understand how DNS works, how to read and edit a DNS zone, and how to configure domain names for your self-hosted services.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Samba title: Samba
description: Set up Samba on Debian to share folders over your local network and access them from Windows, macOS, or Linux.
main: main:
fluid: false fluid: false
--- ---
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: RAID title: RAID
description: Understand RAID concepts — hardware vs software, RAID levels, and how to set up redundant disk arrays for your homelab.
main: main:
fluid: false fluid: false
--- ---
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: ZFS title: ZFS
description: Introduction to ZFS — a combined file system and volume manager with snapshots, checksums, and built-in redundancy for reliable homelab storage.
main: main:
fluid: false fluid: false
--- ---
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: The Basics title: The Basics
description: Overview of server hardware fundamentals — CPUs, RAM, storage, and form factors to understand before building your homelab.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Network title: Network
description: Overview of networking hardware for homelabs — switches, NICs, cables, and how to connect your servers efficiently.
main: main:
fluid: false fluid: false
--- ---
@@ -0,0 +1,83 @@
---
navigation: true
title: The ProloNAS
description: Build a capable home server on a budget using an Intel N100 mini PC — a practical guide to getting started with self-hosting for under $130.
fluid: false
---
:ellipsis{left=0px width=40rem top=10rem blur=140px}
# The ProloNAS
When you decide to dive into the adventure of running your own home server, the same questions usually come up: _“Where should I start?”_, _“Isnt it expensive?”_. And often, people either give up or end up buying a proprietary NAS that theyll throw away a year later once they realize it only brings headaches and wasted money.
A server isnt a piece of furniture. Its simply any computer capable of running Linux.Thats why mini PCs powered by **Intel N100** processors are so popular: for around $100130 on Chinese platforms, you can get a machine that runs **24/7** for years, capable of handling everything youd expect from a home server or personal cloud without sacrificing performance.
Its **objectively inexpensive**, and anyone with a bit of curiosity can get started.
A mini PC for $100 + a USB dock for $50 that holds multiple hard drives = a complete platform for $150, versus **$3501200** for branded NAS systems.
Thats all a **ProloNAS** is. Its then up to you to scale your storage capacity according to your needs.
![](/img/global/prolonas.svg)
## Example Hardware
- Mini PC — **Note: choose 16 GB / 512 GB**: [Aliexpress](https://fr.aliexpress.com/item/1005008477986765.html)
- DAS (Direct Attached Storage) — **Note: select “EU plug”**: [Aliexpress](https://fr.aliexpress.com/item/1005007933987260.html)
- More refined alternative with a fan: [Amazon](https://www.amazon.fr/Boîtier-Disque-Ventilateur-Supportant-Capacité/dp/B0DD3GSSCX)
> *These are not affiliate links — buy wherever you prefer.*
## Why a NAS?
A **NAS** (Network Attached Storage) is a machine centered around storage, designed to be shared over a network.The idea is to have a **reliable and secure** storage space that serves as the backbone for your personal services and apps such as a self-hosted cloud like [Nextcloud](/serveex/cloud/nextcloud), a photo sync tool like [Immich](/serveex/cloud/immich), or a media server like [Plex](/serveex/media/plex). You can also store camera footage, backups, or even development projects on it.
### But why not just use a mini PC with an external hard drive?
Sure, a simple mini PC with 12 TB of storage will do for most people.And your movie collection might fit on an external drive of a few extra terabytes. But thats **neither reliable nor scalable** a single shock or hardware failure could permanently destroy your data.
A real NAS is built around **storage reliability**. It uses redundancy strategies like [RAID](/general/storage/raid) to protect against drive failure, and snapshot systems like [ZFS](/general/storage/zfs) to guard against corruption.
In short, a NAS lets you **host everything yourself** that you currently entrust to third parties while maintaining control, reliability, and data safety.
## The Problem with Consumer NAS Systems
Many brands offer “ready-to-use” NAS platforms: Synology, QNAP, Ugreen, and others. They promise simplicity and sleek web interfaces, but the reality is quite different.
### First, the price.
$350 is the starting price for a 2-bay NAS (without drives) from Synology. For that, you get a 2019 processor, no SSD slot for the OS, and a measly 2 GB of RAM.
Now, compare that to the **ProloNAS**: an N100 (4 cores), 16 GB RAM, a 512 GB SSD for $100130, plus a 4-bay DAS for $55. Thats **half the price** of a 2-bay Synology, and **a quarter of the price** of a 4-bay one.
### Locked-Down Operating Systems
“Yeah, but at least with a Synology, you plug it in and everything just works.”
One year.
Thats how long it took before I threw away my Synology and realized I should have started with a **ProloNAS** (which later became a full-fledged server).
Manufacturers ship heavily customized Linux-based OSes: ancient kernels, limited app repositories, and complete dependence on their proprietary tools. As a result, you cant fully tailor your NAS to your needs, and many Docker containers simply wont run because the kernel is too old.
### Total Vendor Lock-In
“Im fine with the built-in apps.”
Yeah, I thought so too… until my needs exploded: media center, password manager, Git hosting, strong authentication, web hosting, and more.
Why stay stuck with half-baked proprietary tools when you can rely on **open-source projects** that are regularly updated and interoperable?
And what happens when the manufacturer decides to drop support or limit hardware compatibility? Its already happened, Synology made certain drives **incompatible** unless they were “certified” by them. They even **disabled hardware transcoding** on their NAS units: [see here](https://www.cachem.fr/synology-desactive-transcodage-materiel-nas/).
In short, you have **no control** over a product that isnt open, nor truly yours.
## OK, but how do I turn my Mini PC Serveex into a ProloNAS?
As mentioned earlier: by adding a **DAS (drive hub)** and setting up a redundant storage system with [RAID](/general/storage/raid) and [ZFS](/general/storage/zfs), you can transform your mini PC into a robust and scalable NAS.
Enjoy !
+2 -1
View File
@@ -2,6 +2,7 @@
icon: lucide:bookmark icon: lucide:bookmark
navigation: true navigation: true
title: Introduction title: Introduction
description: Introduction to Serveex — a personal homelab project to self-host everyday services using Debian and Docker, replacing Google, Apple, and Netflix.
main: main:
fluid: false fluid: false
--- ---
@@ -41,7 +42,7 @@ The Core of the Server
#title #title
__Operating System__ __Operating System__
#description #description
[Install and configure Debian 12](/serveex/core/installation) [Install and configure Debian 13](/serveex/core/installation)
:: ::
::card{icon=logos:docker-icon} ::card{icon=logos:docker-icon}
+7 -6
View File
@@ -1,21 +1,22 @@
--- ---
navigation: true navigation: true
title: Debian 12 title: Debian 13
description: Step-by-step guide to install Debian 13 on a home server and set up SSH access, essential packages, and a ready-to-use base system.
main: main:
fluid: false fluid: false
--- ---
:ellipsis{left=0px width=40rem top=10rem blur=140px} :ellipsis{left=0px width=40rem top=10rem blur=140px}
# Debian 12 # Debian 13
::alert{type="info"} ::alert{type="info"}
🎯 __Goal:__ Install Debian 12 and the main dependencies to have a ready-to-use OS, accessible via SSH. 🎯 __Goal:__ Install Debian 13 and the main dependencies to have a ready-to-use OS, accessible via SSH.
:: ::
![picture](/img/serveex/server.svg) ![picture](/img/serveex/server.svg)
## Installation ## Installation
--- ---
1. [BIOS Setup](https://www.debian.org/releases/stable/i386/ch03s06.fr.html#bios-setup) 1. [BIOS Setup]((https://www.debian.org/releases/stable/i386/ch03s06.en.html#bios-setup)
2. [Download Debian Image](https://www.debian.org/download.fr.html) 2. [Download Debian Image](https://www.debian.org/download.en.html)
3. [Create Bootable USB (Rufus)](https://dev.to/devops2808/how-to-create-bootable-usb-installer-for-debian-12-4f66) 3. [Create Bootable USB (Rufus)](https://dev.to/devops2808/how-to-create-bootable-usb-installer-for-debian-12-4f66)
4. [Install Debian and Set Up SSH](https://www.howtoforge.com/tutorial/debian-minimal-server/) 4. [Install Debian and Set Up SSH](https://www.howtoforge.com/tutorial/debian-minimal-server/)
5. Install sudo and add a user to the sudo group for administrative privileges. 5. Install sudo and add a user to the sudo group for administrative privileges.
@@ -45,7 +46,7 @@ Some essential apps youll likely need at some point, so might as well install
```sh ```sh
sudo apt update sudo apt update
sudo apt upgrade sudo apt upgrade
sudo apt install vim btop ranger git duf neofetch samba cifs-utils tree unzip ufw sudo apt install vim btop ranger git duf neofetch samba cifs-utils tree unzip
``` ```
Additionally: Additionally:
+4 -3
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Docker title: Docker
description: Install Docker and Dockge on Debian to deploy and manage self-hosted services with simple container stacks.
main: main:
fluid: false fluid: false
--- ---
@@ -43,7 +44,7 @@ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin
That's it! That's it!
**More options:** [Install Docker for Debian 12](https://docs.docker.com/engine/install/debian/) **More options:** [Install Docker for Debian 13](https://docs.docker.com/engine/install/debian/)
::alert{type="info" icon="exclamation-circle"} ::alert{type="info" icon="exclamation-circle"}
:::list{type="info"} :::list{type="info"}
@@ -118,7 +119,7 @@ More info on [Dockge and how to use it](https://github.com/louislam/dockge)
And there you go — Docker and a tool to easily manage your containers are ready! And there you go — Docker and a tool to easily manage your containers are ready!
## [Watchtower](https://github.com/containrrr/watchtower?tab=readme-ov-file), to auto-update containers ## [Watchtower](https://watchtower.nickfedor.com/), to auto-update containers
--- ---
Watchtower is a container that checks for updates and pulls new images automatically, just by adding a label in your containers `compose.yml` files. Watchtower is a container that checks for updates and pulls new images automatically, just by adding a label in your containers `compose.yml` files.
@@ -134,7 +135,7 @@ Watchtower is a container that checks for updates and pulls new images automatic
services: services:
watchtower: watchtower:
container_name: watchtower container_name: watchtower
image: containrrr/watchtower:latest image: ghcr.io/nicholas-fedor/watchtower:latest
restart: unless-stopped restart: unless-stopped
env_file: env_file:
- .env - .env
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: SWAG title: SWAG
description: Set up SWAG as a reverse proxy with automatic SSL, expose your services securely, and configure geo-blocking on your homelab.
main: main:
fluid: false fluid: false
--- ---
+86 -95
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Wireguard title: Wireguard
description: Install and configure WireGuard VPN to securely access your homelab from anywhere and connect all your devices to your private network.
main: main:
fluid: false fluid: false
--- ---
@@ -47,21 +48,21 @@ You *can* allow VPN clients to share access to their local networks, but we won
So only VPN-connected devices can communicate with each other on the VPN, not with other local devices outside the VPN. So only VPN-connected devices can communicate with each other on the VPN, not with other local devices outside the VPN.
## Server Side ## Server Setup
--- ---
::alert{type="info"} ::alert{type="info"}
📋 __Checklist:__ 📋 **Pre-flight Checklist:**
- Ensure port `51820 UDP` is available and properly forwarded through your router to the server (`Source 51820 UDP -> Destination 51820 UDP -> Server`). - Ensure port `51820 UDP` is free on your server and correctly forwarded from your router (`51820 UDP -> Server`).
- Ensure port `51821 TCP` is available for the web UI. - Ensure port `51821 TCP` is free for the web UI.
:: ::
::alert{type="warning"} ::alert{type="warning"}
:::list{type="warning"} :::list{type="warning"}
- __Warning:__ This guide uses version `14` of [wg-easy](https://wg-easy.github.io/wg-easy/latest/). Version `15` introduces breaking changes incompatible with this configuration. - __Warning__: If your IP is not static, use a Dynamic DNS service ([DynDNS](https://en.wikipedia.org/wiki/Dynamic_DNS)). If your ISP uses [CGNAT](https://en.wikipedia.org/wiki/Carrier-grade_NAT), youll need to use an external VPS and connect your local server as a client.
::: :::
:: ::
Folder structure: ### Folder Structure
```sh ```sh
root root
@@ -73,104 +74,98 @@ root
└── .env └── .env
``` ```
The container runs in `HOST` mode, meaning it uses the hosts network stack directly. Open Dockge, click **Compose**, and name the stack `wg_easy`.
Open Dockge, click `compose`, and name the stack `wg_easy`. Copy the following configuration:
Paste the following configuration:
```yaml ```yaml
--- ---
services: services:
wg-easy: wg-easy:
network_mode: host
env_file:
- .env
environment: environment:
- LANG=en - INSECURE=true
- WG_HOST=${HOST} image: ghcr.io/wg-easy/wg-easy:15
- PASSWORD_HASH=${PW}
- WG_DEFAULT_ADDRESS=${ADDRESS}
- WG_HIDE_KEYS=never
- WG_ALLOWED_IPS=${IPS}
- WG_DEFAULT_DNS=
- UI_TRAFFIC_STATS=true
- UI_CHART_TYPE=1
image: ghcr.io/wg-easy/wg-easy:14
container_name: wg-easy container_name: wg-easy
networks:
wg:
ipv4_address: 10.42.42.42
ipv6_address: fdcc:ad94:bacf:61a3::2a
volumes: volumes:
- /docker/wg_easy/config/etc_wireguard:/etc/wireguard - ./etc_wireguard:/etc/wireguard
- /lib/modules:/lib/modules:ro
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
restart: unless-stopped restart: unless-stopped
cap_add: cap_add:
- NET_ADMIN - NET_ADMIN
- SYS_MODULE - SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.all.forwarding=1
- net.ipv6.conf.default.forwarding=1
networks:
wg:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 10.42.42.0/24
- subnet: fdcc:ad94:bacf:61a3::/64
``` ```
::alert{type="success"} ::alert{type="success"}
__Tip:__ **Tip:**
- You can also specify your own wireguard port with `WG_PORT` - You can customize WireGuard and web UI ports.
- Add the Watchtower label to enable automatic updates - Add a Watchtower label for automatic updates:
```yaml ```yaml
services services:
wg-easy: wg-easy:
#... # ...
labels: labels:
- com.centurylinklabs.watchtower.enable=true - com.centurylinklabs.watchtower.enable=true
``` ```
:: ::
In `.env`: Deploy the stack and access the local web UI at `http://server-ip:51821`.
```properties
HOST=
PW=
ADDRESS=
IPS=
```
| Variable | Description | Example |
|--------------|-------------|---------|
| `HOST` | IP of public access of your host (router ISP's IP if it's at home) | `80.75.137.27` |
| `PW` | Bcrypt password hash, [generate here](https://bcrypt-generator.com/). **NOTE:** Double the `$` characters | `$$2a$$12$$FF6T4QqSP9Ho` |
| `ADDRESS` | VPN DHCP address range, the `x` must remain, others can vary | `10.8.0.x` |
| `IPS` | IPs routed by clients through the VPN. Use `10.8.0.0/24` to only route VPN traffic. To include local LAN, add `192.168.0.0/16` separated by commas. | `10.8.0.0/24` |
Deploy the stack.
### Enable Forwarding on Host
To allow communication between VPN clients, enable:
```sh
sudo sysctl net.ipv4.ip_forward=1
sudo sysctl net.ipv4.conf.all.src_valid_mark=1
```
### Retrieve Configuration Files
To configure clients, download the config files from the server:
- Visit `http://your-server-ip:51821`
- Create a client
- Download the config file
- Rename it to `wg0.conf`
::alert{type="danger"} ::alert{type="danger"}
:::list{type="danger"} :::list{type="danger"}
- If it fails, check firewall rules. - If the deployment fails, check your firewall rules.
::: :::
:: ::
## On the Client Server Once connected, follow the web UI instructions to:
- Create your admin account and password.
- Set the host field (use your public IP or domain name).
Then go to *Administrator → Admin Panel → Config*:
- Change `Allowed IPs` from `0.0.0.0/24` to `10.8.0.0/24` for **split tunneling**.
- Remove IPv6 (it often causes unnecessary issues).
### Retrieve Configuration Files
To configure clients:
1. Access the web UI: `http://server-ip:51821`
2. Create a new client
3. Edit the client and add `10.8.0.0/24` to `Server Allowed IPs`
4. (Optional) Set `Persistent Keep Alive` to `25` if its a permanently connected client
5. Save, download, and rename the file to `wg0.conf` (or `wg1.conf`, etc.)
## Client Server Setup
--- ---
::alert{type="info"} ::alert{type="info"}
:::list{type="info"} :::list{type="info"}
- Assumes the client is a Linux server with Docker installed - We assume the client server runs Linux with Docker installed.
::: :::
:: ::
Folder structure: ### Folder Structure
```sh ```sh
root root
@@ -181,33 +176,32 @@ root
└── compose.yaml └── compose.yaml
``` ```
Create the folder `/docker/wireguard/config/wg_confs`: Create the folder:
::alert{type="success"}
__Tip:__ Use [File Browser](/serveex/files/file-browser) to browse and edit files without terminal
::
```sh ```sh
sudo mkdir -p /docker/wireguard/config/wg_confs sudo mkdir -p /docker/wireguard/config/wg_confs
``` ```
Copy the `wg0.conf` file downloaded earlier: ::alert{type="success"}
**Tip:** You can use [File Browser](/serveex/files/file-browser) instead of the terminal to edit and upload files.
::
Create the `wg0.conf` file:
```sh
sudo vi /docker/wireguard/config/wg_confs/wg0.conf
```
Enter insert mode (`i`), paste the downloaded configuration, then save (`Esc``:x`).
::alert{type="success"} ::alert{type="success"}
__Tip:__ Easiest way is to transfer the file via SFTP to `/home/youruser`, then move it: **Alternative method:** Transfer the file via SFTP and move it:
```sh ```sh
sudo cp ~/wg0.conf /docker/wireguard/config/wg_confs sudo cp ~/wg0.conf /docker/wireguard/config/wg_confs
``` ```
:: ::
Create `compose.yaml` in `/docker/wireguard`: Create the `compose.yaml` file in `/docker/wireguard`:
```sh
sudo vi /docker/wireguard/compose.yaml
```
Press `i` to enter insert mode and paste:
```yaml ```yaml
services: services:
@@ -217,42 +211,39 @@ services:
network_mode: host network_mode: host
cap_add: cap_add:
- NET_ADMIN - NET_ADMIN
- SYS_MODULE #optional - SYS_MODULE
environment: environment:
- TZ=Europe/Paris - TZ=Europe/Paris
volumes: volumes:
- /docker/wireguard/config:/config - /docker/wireguard/config:/config
- /lib/modules:/lib/modules #optional - /lib/modules:/lib/modules
restart: unless-stopped restart: unless-stopped
``` ```
Press `Esc` then type `:x` to save and exit.
Start the container: Start the container:
```sh ```sh
cd /docker/wireguard cd /docker/wireguard
sudo docker compose up -d sudo docker compose up -d
``` ```
::alert{type="info" icon="exclamation-circle"} ::alert{type="info"}
:::list{type="info"} :::list{type="info"}
- Repeat for each client - Repeat this setup for each client.
::: :::
:: ::
## Other Devices ## Other Devices
--- ---
- **Phone:** Install Wireguard and scan the QR code from the web UI (`http://your-server-ip:51821`) - **Mobile:** Install WireGuard and scan the QR code via the web UI (`http://server-ip:51821`)
- **PC:** Install the Wireguard client and import the config file - **Desktop:** Install the WireGuard client and import the downloaded config file.
::alert{type="warning"} ::alert{type="warning"}
:::list{type="warning"} :::list{type="warning"}
- __Warning:__ If a client device is on the same LAN as the server, edit `wg0.conf` and change the endpoint to the local server IP: - **Note:** If the client machine is on the same local network as the server, edit the `wg0.conf` file to use the local server IP:
`Endpoint = your-server-ip:51820` `Endpoint = server-local-ip:51820`
::: :::
:: ::
And this is the result: And heres the final setup overview:
![picture](/img/serveex/wireguard.svg) ![picture](/img/serveex/wireguard.svg)
+5 -4
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Authentik title: Authentik
description: Install Authentik as a self-hosted identity provider — configure MFA and protect your services with SSO and reverse proxy authentication.
main: main:
fluid: false fluid: false
--- ---
@@ -57,7 +58,7 @@ Create the folders:
sudo mkdir -p /docker/authentik/media /docker/authentik/certs /docker/authentik/custom-template /docker/authentik/ssh sudo mkdir -p /docker/authentik/media /docker/authentik/certs /docker/authentik/custom-template /docker/authentik/ssh
``` ```
Navigate to the `authentik` folder and generate a password and secret key to include in the `.env` file: Navigate to the `authentik` folder via `cd /docker/authentik` and generate a password and secret key to include in the `.env` file:
```sh ```sh
sudo echo "PG_PASS=$(openssl rand 36 | base64)" >> .env sudo echo "PG_PASS=$(openssl rand 36 | base64)" >> .env
@@ -73,7 +74,7 @@ sudo echo "AUTHENTIK_SECRET_KEY=$(openssl rand 60 | base64)" >> .env
:: ::
Open Dockge and search for "authentik" in the inactive stacks. Open Dockge and search for "authentik" in the inactive stacks.
Name the stack `authentik` and paste the following configuration, replacing `{AUTHENTIK_TAG:-2025.6.3}`{lang=properties} with [the latest version of Authentik](https://goauthentik.io/docs/releases). Name the stack `authentik` and paste the following configuration, replacing `{AUTHENTIK_TAG:-2026.2}`{lang=properties} with [the latest version of Authentik](https://goauthentik.io/docs/releases).
```yaml ```yaml
--- ---
@@ -117,7 +118,7 @@ services:
- redis:/data - redis:/data
server: server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.2.1} image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.2}
container_name: authentik-server container_name: authentik-server
restart: unless-stopped restart: unless-stopped
command: server command: server
@@ -141,7 +142,7 @@ services:
- redis - redis
worker: worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.2.1} image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.2}
container_name: authentik-worker container_name: authentik-worker
restart: unless-stopped restart: unless-stopped
command: worker command: worker
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Cloudflare Zero Trust title: Cloudflare Zero Trust
description: Use Cloudflare Tunnels and Zero Trust to expose homelab services without opening ports — configure SWAG and manage multiple tunnels.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Uptime-Kuma title: Uptime-Kuma
description: Install Uptime-Kuma to monitor your self-hosted services uptime, set up alerts, and optionally protect the dashboard with Authentik.
main: main:
fluid: false fluid: false
--- ---
@@ -36,7 +37,7 @@ Open Dockge, click on `compose`, name the stack `uptime-kuma`, then copy and pas
--- ---
services: services:
uptime-kuma: uptime-kuma:
image: louislam/uptime-kuma:1 image: louislam/uptime-kuma:2-slim
container_name: uptime-kuma container_name: uptime-kuma
volumes: volumes:
- /docker/uptime-kuma/uptime-kuma-data:/app/data - /docker/uptime-kuma/uptime-kuma-data:/app/data
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Dozzle title: Dozzle
description: Install Dozzle to monitor Docker container logs in real time from a clean web interface, exposed via SWAG.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Speedtest Tracker title: Speedtest Tracker
description: Install Speedtest Tracker to automatically measure and log your internet connection speed over time, exposed with SWAG.
main: main:
fluid: false fluid: false
--- ---
@@ -53,7 +54,7 @@ services:
restart: unless-stopped restart: unless-stopped
container_name: speedtest-tracker container_name: speedtest-tracker
ports: ports:
- ${PORT}$:80 - ${PORT}:80
environment: environment:
- PUID=${PUID} - PUID=${PUID}
- PGID=${GUID} - PGID=${GUID}
@@ -75,7 +76,7 @@ In the `.env` file, set the variable `API_KEY` with the key you generated and ad
```properties ```properties
SCHEDULE=15 */6 * * * # every 6 hours SCHEDULE=15 */6 * * * # every 6 hours
KEY=base64:zihejehkj8_nzhY/OjeieR= # your key API_KEY=base64:zihejehkj8_nzhY/OjeieR= # your key
PUID=1000 PUID=1000
GUID=1000 GUID=1000
PORT=3225 # port to access the web UI PORT=3225 # port to access the web UI
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Beszel title: Beszel
description: Install Beszel to monitor server CPU, RAM, disk, and network metrics — including remote servers — with a lightweight web dashboard.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: UpSnap title: UpSnap
description: Install UpSnap to remotely wake up machines on your local network via Wake-on-LAN, exposed with SWAG.
main: main:
fluid: false fluid: false
--- ---
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Plex title: Plex
description: Install Plex Media Server with Tautulli on your homelab to stream movies and TV shows from anywhere on all your devices.
main: main:
fluid: false fluid: false
--- ---
+7 -6
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Qbittorrent title: Qbittorrent
description: Install qBittorrent with Gluetun and ProtonVPN to download torrents securely behind a VPN on your self-hosted server.
main: main:
fluid: false fluid: false
--- ---
@@ -13,7 +14,7 @@ main:
- Securely connect to the BitTorrent network using Gluetun and Proton VPN - Securely connect to the BitTorrent network using Gluetun and Proton VPN
:: ::
![Picture](https://github.com/VueTorrent/VueTorrent/blob/master/public/screenshots/screenshot-desktop-dark-mode.jpeg?raw=true) ![Picture](/img/serveex/qbit-vue.jpeg)
To safely download your favorite media, we'll build a system using: To safely download your favorite media, we'll build a system using:
@@ -59,11 +60,11 @@ Open Dockge, click on `compose`, and name the stack `seedbox`. Paste the followi
services: services:
qbit: qbit:
image: ghcr.io/linuxserver/qbittorrent:latest image: ghcr.io/linuxserver/qbittorrent:libtorrentv1
container_name: qbittorrent container_name: qbittorrent
restart: unless-stopped restart: unless-stopped
network_mode: service:gluetun network_mode: service:gluetun
mem_limit: 1g mem_limit: 4g
environment: environment:
- DOCKER_MODS=ghcr.io/gabe565/linuxserver-mod-vuetorrent|ghcr.io/t-anc/gsp-qbittorent-gluetun-sync-port-mod:main - DOCKER_MODS=ghcr.io/gabe565/linuxserver-mod-vuetorrent|ghcr.io/t-anc/gsp-qbittorent-gluetun-sync-port-mod:main
- TZ=Europe/Paris - TZ=Europe/Paris
@@ -80,10 +81,10 @@ services:
- gluetun - gluetun
gluetun: gluetun:
image: qmcgaw/gluetun:v3.40 image: qmcgaw/gluetun:v3.41.3
container_name: gluetun container_name: gluetun
restart: unless-stopped restart: unless-stopped
mem_limit: 1g mem_limit: 4g
volumes: volumes:
- /docker/gluetun/config.toml:/gluetun/auth/config.toml:ro - /docker/gluetun/config.toml:/gluetun/auth/config.toml:ro
devices: devices:
@@ -149,7 +150,7 @@ Press `i` to edit and enter:
```toml ```toml
[[roles]] [[roles]]
name = "t-anc/GSP-Qbittorent-Gluetun-sync-port-mod" name = "t-anc/GSP-Qbittorent-Gluetun-sync-port-mod"
routes = ["GET /v1/openvpn/portforwarded"] routes = ["GET /v1/portforward"]
auth = "apikey" auth = "apikey"
apikey = "your_key_here" # key you just generated apikey = "your_key_here" # key you just generated
``` ```
+7 -3
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Automation title: Automation
description: Automate media downloads with the Servarr stack — Radarr, Sonarr, Bazarr, Prowlarr, and Overseerr for movies and TV shows.
main: main:
fluid: false fluid: false
--- ---
@@ -160,8 +161,11 @@ services:
bazarr: bazarr:
image: lscr.io/linuxserver/bazarr:latest image: lscr.io/linuxserver/bazarr:latest
container_name: bazarr container_name: bazarr
environment: null restart: unless-stopped
restart: unless-stopped - PUID=1000 - PGID=1000 - TZ=Europe/Paris environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Paris
volumes: volumes:
- /docker/bazarr/config:/config - /docker/bazarr/config:/config
- ${MEDIA_PATH}:/media - ${MEDIA_PATH}:/media
@@ -300,7 +304,7 @@ In *Settings > Apps*, add Radarr and Sonarr with the following details:
--- ---
Bazarr is an app that automatically searches for the correct subtitles in your preferred languages for all the movies and TV shows added by Radarr and Sonarr. Bazarr is an app that automatically searches for the correct subtitles in your preferred languages for all the movies and TV shows added by Radarr and Sonarr.
Go to `http://yourserverip:9696`. Go to `http://yourserverip:6767`.
::alert{type="danger"} ::alert{type="danger"}
:::list{type="danger"} :::list{type="danger"}
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Immich title: Immich
description: Install Immich, a self-hosted alternative to Google Photos and iCloud with face recognition, geolocation, and multi-device sync.
main: main:
fluid: false fluid: false
--- ---
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Nextcloud title: Nextcloud
description: Install Nextcloud to self-host your files, photos, and calendar — a privacy-friendly alternative to Google Drive, OneDrive, and iCloud.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: File Browser title: File Browser
description: Install File Browser to browse and manage your server files from a web interface, exposed securely with SWAG.
main: main:
fluid: false fluid: false
--- ---
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Pingvin title: Pingvin
description: Install Pingvin Share, a self-hosted file sharing platform to send files securely without relying on WeTransfer or Google Drive.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Code-Server title: Code-Server
description: Install code-server to run VS Code in your browser from your homelab — mount folders and expose it securely with SWAG.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Gitea title: Gitea
description: Install Gitea, a lightweight self-hosted Git service to manage your code repositories privately on your own server.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: IT Tools title: IT Tools
description: Install IT Tools, a self-hosted collection of handy utilities for developers — converters, encoders, formatters, and more.
main: main:
fluid: false fluid: false
--- ---
+1
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Adguard Home title: Adguard Home
description: Install AdGuard Home for network-wide ad and tracker blocking with DNS-over-HTTPS, client management, and custom filtering rules.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Vaultwarden title: Vaultwarden
description: Install Vaultwarden, a self-hosted Bitwarden-compatible password manager to replace Google or Apple password managers across all your devices.
main: main:
fluid: false fluid: false
--- ---
@@ -2,6 +2,7 @@
icon: lucide:bookmark icon: lucide:bookmark
navigation: true navigation: true
title: Introduction title: Introduction
description: Introduction to Stockeex — a personal project for stock and inventory management. Documentation coming soon.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Nvidia Stock Bot title: Nvidia Stock Bot
description: A Python bot that monitors GPU stock availability in real time and sends Discord alerts — built during the RTX 5000 series launch shortage.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Adguard CIDRE title: Adguard CIDRE
description: A Python script to sync AdGuard Home CIDR allowlists automatically, securing your self-hosted DNS server exposed to the internet.
main: main:
fluid: false fluid: false
--- ---
+7
View File
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Lumeex title: Lumeex
description: Lumeex is a static photo gallery site generator built with Python — minimalist, lightweight, and fully customizable without a CMS.
main: main:
fluid: false fluid: false
--- ---
@@ -30,6 +31,12 @@ Eventually, after getting good results, I figured I might as well go all the way
Thats how **Lum[eex]{style="color: #1ad6ff"}** was born. Thats how **Lum[eex]{style="color: #1ad6ff"}** was born.
<div align="center">
<img src="https://git.djeex.fr/Djeex/lumeex/raw/branch/main/illustration/lumeex-webui.png" alt="Lumeex Screenshot" />
</div>
---
::card-grid{grid-template-columns="repeat(2, minmax(0, 1fr));"} ::card-grid{grid-template-columns="repeat(2, minmax(0, 1fr));"}
#title #title
Et voilà! Et voilà!
@@ -0,0 +1,58 @@
---
navigation: true
title: Instameex
description: Instameex is a Docker-based tool to merge SDR and HDR photo exports into a proper gain-map JPEG ready for Instagram HDR upload.
main:
fluid: false
---
:ellipsis{left=0px width=40rem top=10rem blur=140px}
<div align="center">
<img src="https://git.djeex.fr/Djeex/instameex/raw/branch/main/src/assets/img/logo-long.svg" alt="Lumeex Screenshot" width="300"/>
</div>
<p/>
<div align="center">
<p>Mix your SDR and HDR exports into an Instagram-ready HDR photo.</p>
</div>
</p>
<div align="center">
<img src="https://git.djeex.fr/Djeex/instameex/raw/branch/main/illustration/instameex-illustration.png" width="640" alt="Instameex Screenshot" />
</div>
---
Nothing is more frustrating than Instagram's HDR handling. It compresses and destroys gain maps, and the slightest change in aspect ratio or size simply strips HDR out entirely. As for Lightroom, its "SDR preview" system is frankly unacceptable, it makes it impossible to get consistent results. Until now, posting on Instagram meant choosing between decent SDR with broken HDR, or the other way around.
Why not simply edit your SDR file to perfection on one side, your HDR file on the other, and then recalculate a gain map from those two perfect files?
A few pioneers have already gone down that road, notably with an [Adobe Lightroom Classic](https://github.com/karachungen/lightroom-plugin-export-hdr) plugin. Judge me if you want, but I only use Lightroom CC, which does not support plugins.
I drew inspiration from a [fork of the original project](https://github.com/kostis-kounadis/instagram-hdr-assembler), the one that eventually became the LrC plugin, to build a frontend that can be easily deployed with Docker. Let's be honest: it was also a great excuse to put my Claude Code subscription to the test. And I have to say, watching it spin up its own environments, run end-to-end tests, self-correct its code, and write detailed summaries is genuinely impressive. I still reviewed everything myself, don't worry. I also learned a great deal about HDR fundamentals, gain maps, HLG/PQ tone curves, color spaces, and more.
In short, here is what my workflow now looks like for posting on Instagram:
![Instameex workflow](/img/nonsense/instameex-workflow.svg)
Allow me to introduce **Instam[eex]{style="color: #1ad6ff"}**
---
::card-grid{grid-template-columns="repeat(2, minmax(0, 1fr));"}
#title
And here is the result
#root
:ellipsis{left=0px width=40rem top=10rem blur=140px}
#default
::card
#title
🐋 __Instameex__
#description
[Open the repository](https://git.djeex.fr/Djeex/instameex)
::
::card
#title
🌍 __Online version__
#description
[Convert online](https://instameex.djeex.fr)
::
::
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: Servarr corrector title: Servarr corrector
description: A bash script to detect and fix duplicate media files in Sonarr and Radarr libraries by replacing copies with hardlinks to reclaim disk space.
main: main:
fluid: false fluid: false
--- ---
@@ -1,6 +1,7 @@
--- ---
navigation: true navigation: true
title: LUKS Backup title: LUKS Backup
description: A bash script to automatically dump LUKS headers from all encrypted disks, identify them by serial number, and store them in an encrypted archive.
main: main:
fluid: false fluid: false
--- ---
@@ -0,0 +1,89 @@
---
navigation: true
title: Socat Proxy
description: Use socat to proxy the Docker socket through Docker Socket Proxy, allowing Beszel to collect container stats without exposing the full Docker socket.
main:
fluid: false
---
:ellipsis{left=0px width=40rem top=10rem blur=140px}
# Socat Proxy
---
This project addresses a common use case:
- I have [Beszel](https://beszel.dev/), a monitoring container running in host mode, which requires access to the Docker socket to collect container statistics.
- To avoid exposing the Docker socket fully to Beszel, I use [Docker Socket Proxy](https://github.com/Tecnativa/docker-socket-proxy), a container that sits between the Docker socket and the consuming container. It filters requests by setting appropriate permissions, preventing full exposure of the Docker socket.
The problem arises when **Beszel** runs in host mode. In that case, it must connect directly to **Docker Socket Proxy** on a host port, meaning the proxys port is exposed. This allows any container or application on the host to access it and use the Docker socket.
This is where [Socat Proxy](https://git.djeex.fr/Djeex/socat-proxy) comes in. It is a container that:
- Creates a UNIX socket
- Listens on this socket
- Forwards requests to Docker Socket Proxy and back
- Replaces the real Docker socket by exposing the proxy socket in the target container via a bind mount (in this case, Beszel)
With this setup, Docker Socket Proxy communicates with Socat Proxy in their isolated bridge network, while the UNIX socket bind-mounted on the host has restricted permissions, preventing access from other containers or applications.
In short:
![](/img/nonsense/socat-proxy.svg)
For example, with Beszel, the configuration would look like this:
```yaml
services:
socat-proxy:
image: git.djeex.fr/djeex/socat-proxy:latest
container_name: socat-proxy-beszel
environment:
- TARGET_HOST=${TARGET_HOST}
- TARGET_PORT=${TARGET_PORT}
- UNIX_SOCKET_PATH=${UNIX_SOCKET_PATH}
- HOST_SOCKET_PATH=${HOST_SOCKET_PATH}
- UNIX_SOCKET_NAME=${UNIX_SOCKET_NAME}
volumes:
- ${HOST_SOCKET_PATH}:${UNIX_SOCKET_PATH}
restart: unless-stopped
depends_on:
- ${TARGET_HOST}
socket-proxy:
image: lscr.io/linuxserver/socket-proxy:latest
container_name: ${TARGET_HOST}
security_opt:
- no-new-privileges:true
environment:
- CONTAINERS=1
- INFO=1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
read_only: true
tmpfs:
- /run
beszel-agent:
image: henrygd/beszel-agent:latest
container_name: beszel-agent
restart: unless-stopped
network_mode: host
security_opt:
- no-new-privileges:true
volumes:
- ${HOST_SOCKET_PATH}/${UNIX_SOCKET_NAME}:/var/run/docker.sock:ro
environment:
- #... your Beszel environment variables
depends_on:
- socat-proxy
```
More information is available on the repository:
::card
#title
🐋 **Socat Proxy**
#description
[A lightweight bind-mount socket proxy](https://git.djeex.fr/Djeex/socat-proxy)
::
+52
View File
@@ -0,0 +1,52 @@
---
navigation: true
title: HotDisk
description: A bash script that monitors hard drive temperatures and automatically shuts down the server when disks stay above a safe threshold for too long.
main:
fluid: false
---
:ellipsis{left=0px width=40rem top=10rem blur=140px}
# HotDisk
---
When you have a NAS with several drives sitting in a laundry room, temperatures can quickly rise.
Hard drives are very sensitive to heat and can suffer serious damage if they exceed a certain temperature threshold for too long.
After a particularly hot summer that caused a few cold sweats while monitoring my drives temperatures, I started looking for a way to automatically shut down the server when disk temperatures stay above their safe limit for an extended period.
Since I couldnt find a convincing solution, I decided to build my own.
- The script reads SMART temperature data from all SATA drives every minute.
- It counts the number of consecutive minutes the temperature stays above or below the threshold.
- It sends Discord notifications if the threshold is exceeded or when the temperature cools down.
- It triggers a system shutdown if the temperature stays above the limit for the configured duration.
- It logs all temperatures and counter states, and automatically rotates log files.
While I was at it, I also added an installation script that installs the main script, makes it executable, creates a systemd service and timer, and enables them automatically.
The installer also lets you configure various parameters:
| Variable | Description | Default Value |
|-----------------------|------------------------------------------------------------------------------|-----------------------------------------------|
| `MAX_TEMP` | Maximum allowed temperature (°C) before the shutdown countdown starts | `60` |
| `HOT_DURATION` | Consecutive minutes above `MAX_TEMP` before shutdown | `5` |
| `COOL_RESET_DURATION` | Consecutive minutes below `MAX_TEMP` to reset all counters | `5` |
| `LOG_FILE` | Path to the main log file | `/var/log/hdd_temp_monitor.log` |
| `LOG_ROTATE_COUNT` | Number of log files to keep | `7` |
| `LOG_ROTATE_PERIOD` | Log rotation period (`daily` or `weekly`) | `daily` |
| `DISCORD_WEBHOOK` | Discord webhook URL for notifications | _Required_ |
It also runs another script that configures **logrotate** with the parameters defined above.
Finally, the installer can even be executed directly via a simple `curl` command followed by one last setup script — perfect for the laziest of us.
I also had to handle several tricky cases: running as root without sudo, using sudo directly, running as a non-sudo user, missing dependencies, permission issues, file creation errors, disk data reading errors, and more.
Concurrent access to the status file also had to be managed carefully.
More details are available directly on the repository:
::card
#title
📜 __HotDisk__
#description
[Keep your drives cool!](https://git.djeex.fr/Djeex/hotdisk)
::
@@ -0,0 +1,118 @@
---
navigation: true
title: Backrest Docker Stop
description: A bash script that stops Docker containers before a Backrest backup runs and restarts them after — ensuring safe database backups without complex dumps.
main:
fluid: false
---
:ellipsis{left=0px width=40rem top=10rem blur=140px}
# Backrest Docker Stop
---
[Backrest](https://github.com/garethgeorge/backrest) is a fantastic backup tool. In the case of [Serveex](https://docu.djeex.fr/serveex/introduction), most of the data that needs to be backed up consists of containers, and those containers often include databases.
The problem? You cant safely back up a database while its running. There are plenty of complex solutions involving database dumps, but often the simplest method is to stop the containers, perform the backup, and then restart them.
**Backrest** doesnt natively provide this functionality, but it does allow the execution of custom scripts triggered by events, for example, at the start and end of a backup plan. Our goal is to stop the containers whose databases need to be backed up when the backup plan starts, and restart them when the backup plan finishes.To achieve this, well need a small Bash script and a secure connection between Backrest and the Docker socket, to enable the following sequence:
- The backup plan starts
- The event triggers the execution of a custom script
- The script contacts Docker and retrieves a list of containers labeled `backrest.backup.stop=true`
- It stops those containers
- The backup plan completes
- The event triggers another custom script
- The script contacts Docker again, retrieves the same list, and restarts those containers
## Securely Connecting Backrest and Docker
To allow **Backrest** to communicate securely with Docker, well use [Docker Socket Proxy](https://github.com/linuxserver/docker-socket-proxy).
This avoids exposing the full Docker socket and grants only the necessary permissions.
Heres an example Docker stack:
```yaml
---
services:
backrest:
image: garethgeorge/backrest:latest
container_name: backrest
hostname: backrest
security_opt:
- no-new-privileges:true
volumes:
- ... # your volumes
environment:
- ... # your environment variables
- DOCKER_HOST=tcp://socket-proxy-backrest:2375
restart: unless-stopped
ports:
- ... # your ports
depends_on:
- socket-proxy
socket-proxy:
image: lscr.io/linuxserver/socket-proxy:latest
container_name: socket-proxy-backrest
security_opt:
- no-new-privileges:true
environment:
- CONTAINERS=1
- ALLOW_START=1
- ALLOW_STOP=1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
read_only: true
tmpfs:
- /run
```
With this setup, Backrest can communicate with Docker safely and securely.
## The Scripts
Below are the scripts to use for **Backrest**s *start* and *end* backup events.
::code-group
```sh [Stop]
#!/usr/bin/env bash
BACKUP_LABEL="backrest.backup.stop=true"
BACKUP_CONTAINERS=$(docker ps -aqf "label=$BACKUP_LABEL")
for BC in $BACKUP_CONTAINERS
do
docker stop "$BC"
done
sleep 10
```
```sh [Start]
#!/usr/bin/env bash
BACKUP_LABEL="backrest.backup.stop=true"
BACKUP_CONTAINERS=$(docker ps -aqf "label=$BACKUP_LABEL")
for BC in $BACKUP_CONTAINERS
do
docker start "$BC"
done
sleep 10
```
::
## The Label
Once the scripts are in place and configured for the proper **Backrest** hooks, you just need to add the label `backrest.backup.stop=true` to the `compose.yaml` files of the containers that should stop and restart during backups:
```yaml
services:
your_service:
...
labels:
- backrest.backup.stop=true
```
And thats it!
At the next backup, all containers with the correct label will automatically stop during the backup and restart once its finished.
@@ -0,0 +1,258 @@
---
navigation: true
title: Wireguard 14
main:
fluid: false
---
:ellipsis{left=0px width=40rem top=10rem blur=140px}
# Wireguard
::alert{type="info"}
🎯 __Goals:__
- Install Wireguard
- Configure clients
- Access the secure network
::
## Introduction
---
Using a VPN allows remote access to a servers local resources without exposing them to the internet. Its a clean and secure way to access services like SSH without exposing the port publicly. With a VPN, you can securely connect to your network from anywhere and make devices on different networks communicate.
Here we will use [Wireguard](https://www.wireguard.com/), a secure and high-performance VPN server, using containers:
- [wg-easy](https://github.com/wg-easy/wg-easy) as the server, providing a very simple web UI to manage connections and download config files (including QR codes for phones)
- [Wireguard](https://docs.linuxserver.io/images/docker-wireguard/?h=wireguard) as the client for Linux systems
Clients are also available for Windows, macOS, iOS, and Android.
The concept:
- On the internet, anyone can reach any internet box and thus any exposed server.
- Your server is on your local network. It is accessible only locally unless services are explicitly exposed (as we did with Dockge). To access non-exposed resources, you must be on the same local network.
- We want to securely access these unexposed services (like SSH) from anywhere.
- We also want to connect services between servers, like linking two Dockge instances securely.
To achieve this, well create a **Virtual Private Network** (VPN), i.e., a secure tunnel that only connected machines can use. Theyll appear to be on the same private network.
Additionally, you can add your phone, laptop, or other devices to the VPN and securely access your server resources wherever you are.
![picture](/img/serveex/vpn.svg)
In this diagram, machine 1 is part of two networks:
- Its local network (devices behind the same router, e.g. `192.168.x.x` machines 1 and 2)
- The VPN network (VPN devices with a second IP, e.g. `10.8.x.x` machines 1 and 4)
You *can* allow VPN clients to share access to their local networks, but we wont do that here for security and subnet conflict reasons (e.g., if two remote machines use the same local IP like `192.168.1.1`).
So only VPN-connected devices can communicate with each other on the VPN, not with other local devices outside the VPN.
## Server Side
---
::alert{type="info"}
📋 __Checklist:__
- Ensure port `51820 UDP` is available and properly forwarded through your router to the server (`Source 51820 UDP -> Destination 51820 UDP -> Server`).
- Ensure port `51821 TCP` is available for the web UI.
::
::alert{type="warning"}
:::list{type="warning"}
- __Warning:__ This guide uses version `14` of [wg-easy](https://wg-easy.github.io/wg-easy/latest/). Version `15` introduces breaking changes incompatible with this configuration.
:::
::
Folder structure:
```sh
root
└── docker
└── wg-easy
├── config
│ └── etc_wireguard
├── compose.yaml
└── .env
```
The container runs in `HOST` mode, meaning it uses the hosts network stack directly.
Open Dockge, click `compose`, and name the stack `wg_easy`.
Paste the following configuration:
```yaml
---
services:
wg-easy:
network_mode: host
env_file:
- .env
environment:
- LANG=en
- WG_HOST=${HOST}
- PASSWORD_HASH=${PW}
- WG_DEFAULT_ADDRESS=${ADDRESS}
- WG_HIDE_KEYS=never
- WG_ALLOWED_IPS=${IPS}
- WG_DEFAULT_DNS=
- UI_TRAFFIC_STATS=true
- UI_CHART_TYPE=1
image: ghcr.io/wg-easy/wg-easy:14
container_name: wg-easy
volumes:
- /docker/wg_easy/config/etc_wireguard:/etc/wireguard
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
```
::alert{type="success"}
__Tip:__
- You can also specify your own wireguard port with `WG_PORT`
- Add the Watchtower label to enable automatic updates
```yaml
services
wg-easy:
#...
labels:
- com.centurylinklabs.watchtower.enable=true
```
::
In `.env`:
```properties
HOST=
PW=
ADDRESS=
IPS=
```
| Variable | Description | Example |
|--------------|-------------|---------|
| `HOST` | IP of public access of your host (router ISP's IP if it's at home) | `80.75.137.27` |
| `PW` | Bcrypt password hash, [generate here](https://bcrypt-generator.com/). **NOTE:** Double the `$` characters | `$$2a$$12$$FF6T4QqSP9Ho` |
| `ADDRESS` | VPN DHCP address range, the `x` must remain, others can vary | `10.8.0.x` |
| `IPS` | IPs routed by clients through the VPN. Use `10.8.0.0/24` to only route VPN traffic. To include local LAN, add `192.168.0.0/16` separated by commas. | `10.8.0.0/24` |
Deploy the stack.
### Enable Forwarding on Host
To allow communication between VPN clients, enable:
```sh
sudo sysctl net.ipv4.ip_forward=1
sudo sysctl net.ipv4.conf.all.src_valid_mark=1
```
### Retrieve Configuration Files
To configure clients, download the config files from the server:
- Visit `http://your-server-ip:51821`
- Create a client
- Download the config file
- Rename it to `wg0.conf`
::alert{type="danger"}
:::list{type="danger"}
- If it fails, check firewall rules.
:::
::
## On the Client Server
---
::alert{type="info"}
:::list{type="info"}
- Assumes the client is a Linux server with Docker installed
:::
::
Folder structure:
```sh
root
└── docker
└── wireguard
└── config
│ └── wg_confs
└── compose.yaml
```
Create the folder `/docker/wireguard/config/wg_confs`:
::alert{type="success"}
__Tip:__ Use [File Browser](/serveex/files/file-browser) to browse and edit files without terminal
::
```sh
sudo mkdir -p /docker/wireguard/config/wg_confs
```
Copy the `wg0.conf` file downloaded earlier:
::alert{type="success"}
__Tip:__ Easiest way is to transfer the file via SFTP to `/home/youruser`, then move it:
```sh
sudo cp ~/wg0.conf /docker/wireguard/config/wg_confs
```
::
Create `compose.yaml` in `/docker/wireguard`:
```sh
sudo vi /docker/wireguard/compose.yaml
```
Press `i` to enter insert mode and paste:
```yaml
services:
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: wireguard
network_mode: host
cap_add:
- NET_ADMIN
- SYS_MODULE #optional
environment:
- TZ=Europe/Paris
volumes:
- /docker/wireguard/config:/config
- /lib/modules:/lib/modules #optional
restart: unless-stopped
```
Press `Esc` then type `:x` to save and exit.
Start the container:
```sh
cd /docker/wireguard
sudo docker compose up -d
```
::alert{type="info"}
:::list{type="info"}
- Repeat for each client
:::
::
## Other Devices
---
- **Phone:** Install Wireguard and scan the QR code from the web UI (`http://your-server-ip:51821`)
- **PC:** Install the Wireguard client and import the config file
::alert{type="warning"}
:::list{type="warning"}
- __Warning:__ If a client device is on the same LAN as the server, edit `wg0.conf` and change the endpoint to the local server IP:
`Endpoint = your-server-ip:51820`
:::
::
And this is the result:
![picture](/img/serveex/wireguard.svg)
+2
View File
@@ -0,0 +1,2 @@
icon: lucide:trash-2
navigation.title: Deprecated
+2
View File
@@ -0,0 +1,2 @@
icon: noto:recycling-symbol
navigation.title: Recycled
+11 -1
View File
@@ -2,6 +2,7 @@ export default defineNuxtConfig({
// https://github.com/nuxt-themes/docus // https://github.com/nuxt-themes/docus
css: ['~/assets/css/extra.css'], css: ['~/assets/css/extra.css'],
extends: ['@nuxt-themes/docus'], extends: ['@nuxt-themes/docus'],
modules: ['@nuxtjs/sitemap'],
devtools: { enabled: false }, devtools: { enabled: false },
colorMode: { colorMode: {
preference: 'dark', preference: 'dark',
@@ -37,10 +38,19 @@ export default defineNuxtConfig({
{ rel: 'manifest', href: '/img/favicon/site.webmanifest' } { rel: 'manifest', href: '/img/favicon/site.webmanifest' }
], ],
meta: [ meta: [
{ name: 'darkreader-lock' }, { name: 'darkreader-lock', content: 'true' },
] ]
} }
}, },
site: {
url: 'https://docu.djeex.fr'
},
sitemap: {
autoLastmod: true,
urls: ['https://docu.djeex.fr']
},
compatibilityDate: '2024-10-24' compatibilityDate: '2024-10-24'
}) })
+10367 -2789
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -15,8 +15,9 @@
"@nuxt/eslint-config": "^0.6.1", "@nuxt/eslint-config": "^0.6.1",
"@nuxt/icon": "^1.7.5", "@nuxt/icon": "^1.7.5",
"@nuxtjs/plausible": "^1.0.3", "@nuxtjs/plausible": "^1.0.3",
"@nuxtjs/sitemap": "6.1.5",
"@types/node": "^22.9.0", "@types/node": "^22.9.0",
"eslint": "^9.14.0", "eslint": "^9.14.0",
"nuxt": "^3.14.159" "nuxt": "^3.21.11"
} }
} }
+13
View File
@@ -0,0 +1,13 @@
export default defineNuxtPlugin(() => {
const route = useRoute()
const canonicalUrl = withSiteUrl(computed(() => route.path), { canonical: true })
useHead({
link: [
{ rel: 'canonical', href: canonicalUrl }
],
meta: [
{ property: 'og:url', content: canonicalUrl }
]
})
})
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 97 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 242 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB