Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3529834d95 | ||
|
|
fd21bd2f83 | ||
|
|
2c28b27e82 | ||
|
|
d22711484b | ||
|
|
bfdef4c47a | ||
|
|
6129fd31d1 | ||
|
|
d839908521 | ||
|
|
c640801e23 | ||
|
|
9e3f116f55 | ||
|
|
a59c6c7d4a | ||
|
|
7f0c36fddf | ||
|
|
3e421f5478 | ||
|
|
ad86a1f3ce | ||
|
|
d2b6fbec5e | ||
|
|
a53a424399 | ||
|
|
77b87485b0 | ||
|
|
a63454ed53 | ||
|
|
104efa534c | ||
|
|
eaabf7db68 | ||
|
|
c1f6cff105 |
+1
-1
@@ -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,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:
|
||||||
|
|||||||
@@ -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,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,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,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,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,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?”_, _“Isn’t it expensive?”_. And often, people either give up or end up buying a proprietary NAS that they’ll throw away a year later once they realize it only brings headaches and wasted money.
|
||||||
|
|
||||||
|
A server isn’t a piece of furniture. It’s simply any computer capable of running Linux.That’s why mini PCs powered by **Intel N100** processors are so popular: for around $100–130 on Chinese platforms, you can get a machine that runs **24/7** for years, capable of handling everything you’d expect from a home server or personal cloud without sacrificing performance.
|
||||||
|
|
||||||
|
It’s **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 **$350–1200** for branded NAS systems.
|
||||||
|
|
||||||
|
That’s all a **ProloNAS** is. It’s then up to you to scale your storage capacity according to your needs.
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 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 1–2 TB of storage will do for most people.And your movie collection might fit on an external drive of a few extra terabytes. But that’s **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 $100–130, plus a 4-bay DAS for $55. That’s **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.
|
||||||
|
That’s 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 can’t fully tailor your NAS to your needs, and many Docker containers simply won’t run because the kernel is too old.
|
||||||
|
|
||||||
|
### Total Vendor Lock-In
|
||||||
|
|
||||||
|
“I’m 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? It’s 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 isn’t 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,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}
|
||||||
|
|||||||
@@ -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.
|
||||||
::
|
::
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 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 you’ll 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:
|
||||||
|
|||||||
@@ -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,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
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -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), you’ll 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 host’s 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 it’s 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 here’s the final setup overview:
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -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,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
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -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
|
||||||
::
|
::
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -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
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -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,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,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,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
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -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
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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 proxy’s 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:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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)
|
||||||
|
::
|
||||||
@@ -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 couldn’t 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 can’t safely back up a database while it’s 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** doesn’t 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, we’ll 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, we’ll use [Docker Socket Proxy](https://github.com/linuxserver/docker-socket-proxy).
|
||||||
|
This avoids exposing the full Docker socket and grants only the necessary permissions.
|
||||||
|
Here’s 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 that’s it!
|
||||||
|
At the next backup, all containers with the correct label will automatically stop during the backup and restart once it’s 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 server’s local resources without exposing them to the internet. It’s 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, we’ll create a **Virtual Private Network** (VPN), i.e., a secure tunnel that only connected machines can use. They’ll 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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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 won’t 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 host’s 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:
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
icon: lucide:trash-2
|
||||||
|
navigation.title: Deprecated
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
icon: noto:recycling-symbol
|
||||||
|
navigation.title: Recycled
|
||||||
+11
-1
@@ -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'
|
||||||
})
|
})
|
||||||
Generated
+10367
-2789
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 |
Reference in New Issue
Block a user