Rework the Serveex intro page and fix icon colors
This commit is contained in:
@@ -1,278 +0,0 @@
|
||||
---
|
||||
title: Wireguard
|
||||
description: Install and configure WireGuard VPN to securely access your homelab from anywhere and connect all your devices to your private network.
|
||||
---
|
||||
|
||||
|
||||
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
|
||||
|
||||
## 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 Setup
|
||||
::note
|
||||
📋 **Pre-flight Checklist:**
|
||||
|
||||
- Ensure port `51820 UDP` is free on your server and correctly forwarded from your router (`51820 UDP -> Server`).
|
||||
- Ensure port `51821 TCP` is free for the web UI.
|
||||
::
|
||||
|
||||
::warning
|
||||
|
||||
__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
|
||||
|
||||
::file-tree
|
||||
---
|
||||
tree:
|
||||
/:
|
||||
- docker:
|
||||
- wg-easy:
|
||||
- config:
|
||||
- etc_wireguard/
|
||||
- compose.yaml
|
||||
- .env
|
||||
---
|
||||
::
|
||||
|
||||
::steps{level="3"}
|
||||
### Deploy the stack
|
||||
|
||||
Open Dockge, click **Compose**, and name the stack `wg_easy`.
|
||||
|
||||
Copy the following configuration:
|
||||
|
||||
```yaml [compose.yaml]
|
||||
---
|
||||
services:
|
||||
wg-easy:
|
||||
environment:
|
||||
- INSECURE=true
|
||||
image: ghcr.io/wg-easy/wg-easy:15
|
||||
container_name: wg-easy
|
||||
networks:
|
||||
wg:
|
||||
ipv4_address: 10.42.42.42
|
||||
ipv6_address: fdcc:ad94:bacf:61a3::2a
|
||||
volumes:
|
||||
- ./etc_wireguard:/etc/wireguard
|
||||
- /lib/modules:/lib/modules:ro
|
||||
ports:
|
||||
- "51820:51820/udp"
|
||||
- "51821:51821/tcp"
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- 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
|
||||
```
|
||||
|
||||
::tip{icon=""}
|
||||
✨ **Tip:**
|
||||
|
||||
- You can customize WireGuard and web UI ports.
|
||||
- Add a Watchtower label for automatic updates:
|
||||
|
||||
```yaml [compose.yaml]
|
||||
---
|
||||
services:
|
||||
wg-easy:
|
||||
# ...
|
||||
labels:
|
||||
- com.centurylinklabs.watchtower.enable=true
|
||||
```
|
||||
::
|
||||
|
||||
Deploy the stack and access the local web UI at `http://server-ip:51821`.
|
||||
|
||||
::caution
|
||||
|
||||
If the deployment fails, check your firewall rules.
|
||||
::
|
||||
|
||||
### Create your account
|
||||
|
||||
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).
|
||||
|
||||
### Configure the tunnel
|
||||
|
||||
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).
|
||||
|
||||
### Done !
|
||||
::
|
||||
|
||||
### Retrieve Configuration Files
|
||||
|
||||
To configure clients:
|
||||
|
||||
::steps{level="4"}
|
||||
#### Access the web UI
|
||||
|
||||
Go to `http://server-ip:51821`.
|
||||
|
||||
#### Create a new client
|
||||
|
||||
#### Edit the client
|
||||
|
||||
Add `10.8.0.0/24` to `Server Allowed IPs`.
|
||||
|
||||
#### (Optional) Set Persistent Keep Alive
|
||||
|
||||
Set it to `25` if it’s a permanently connected client.
|
||||
|
||||
#### Save and rename the file
|
||||
|
||||
Save, download, and rename the file to `wg0.conf` (or `wg1.conf`, etc.)
|
||||
|
||||
#### Done !
|
||||
::
|
||||
|
||||
## Client Server Setup
|
||||
::note
|
||||
|
||||
We assume the client server runs Linux with Docker installed.
|
||||
::
|
||||
|
||||
### Folder Structure
|
||||
|
||||
::file-tree
|
||||
---
|
||||
tree:
|
||||
/:
|
||||
- docker:
|
||||
- wireguard:
|
||||
- config:
|
||||
- wg_confs/
|
||||
- compose.yaml
|
||||
---
|
||||
::
|
||||
|
||||
::steps{level="3"}
|
||||
### Create the folder
|
||||
|
||||
```bash [Terminal]
|
||||
sudo mkdir -p /docker/wireguard/config/wg_confs
|
||||
```
|
||||
|
||||
::tip{icon=""}
|
||||
✨ **Tip:** You can use [File Browser Quantum](/serveex/files/file-browser-quantum) instead of the terminal to edit and upload files.
|
||||
::
|
||||
|
||||
### Create the wg0.conf file
|
||||
|
||||
```bash [Terminal]
|
||||
sudo nano /docker/wireguard/config/wg_confs/wg0.conf
|
||||
```
|
||||
|
||||
Paste the downloaded configuration, then save with :kbd{value="Ctrl+O"}, :kbd{value="Enter"}, and exit with :kbd{value="Ctrl+X"}.
|
||||
|
||||
::tip{icon=""}
|
||||
✨ **Alternative method:** Transfer the file via SFTP and move it:
|
||||
```bash [Terminal]
|
||||
sudo cp ~/wg0.conf /docker/wireguard/config/wg_confs
|
||||
```
|
||||
::
|
||||
|
||||
### Create the compose file
|
||||
|
||||
Create the `compose.yaml` file in `/docker/wireguard`:
|
||||
|
||||
```yaml [compose.yaml]
|
||||
---
|
||||
services:
|
||||
wireguard:
|
||||
image: lscr.io/linuxserver/wireguard:latest
|
||||
container_name: wireguard
|
||||
network_mode: host
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_MODULE
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- /docker/wireguard/config:/config
|
||||
- /lib/modules:/lib/modules
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### Start the container
|
||||
|
||||
```bash [Terminal]
|
||||
cd /docker/wireguard
|
||||
sudo docker compose up -d
|
||||
```
|
||||
|
||||
### Done !
|
||||
::
|
||||
|
||||
::note
|
||||
|
||||
Repeat this setup for each client.
|
||||
::
|
||||
|
||||
## Other Devices
|
||||
|
||||
- **Mobile:** Install WireGuard and scan the QR code via the web UI (`http://server-ip:51821`)
|
||||
- **Desktop:** Install the WireGuard client and import the downloaded config file.
|
||||
|
||||
::warning
|
||||
|
||||
**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 = server-local-ip:51820`
|
||||
::
|
||||
|
||||
And here’s the final setup overview:
|
||||
|
||||

|
||||
+37
-56
@@ -10,16 +10,11 @@ description: Install TinyAuth, a lightweight forward-auth proxy, and pair it wit
|
||||
|
||||

|
||||
|
||||
It supports a simple local username/password login out of the box, and can also delegate login to an external OIDC provider. Here we'll use [Pocket ID](/serveex/security/pocket-id), so anyone visiting a protected app first authenticates with a passkey via Pocket ID, then gets forwarded through.
|
||||
It supports a simple local username/password login out of the box, which is what we'll set up here. It can also delegate login to an external OIDC provider like [Pocket ID](/serveex/security/pocket-id) instead, so anyone visiting a protected app authenticates with a passkey via Pocket ID and then gets forwarded through: install Pocket ID afterwards and follow [its guide](/serveex/security/pocket-id#connecting-pocket-id-to-tinyauth) to connect the two.
|
||||
|
||||
- [TinyAuth documentation](https://tinyauth.app/docs)
|
||||
- [TinyAuth on GitHub](https://github.com/tinyauthapp/tinyauth)
|
||||
|
||||
::note
|
||||
|
||||
This guide assumes you've already installed [Pocket ID](/serveex/security/pocket-id). You can skip the Pocket ID sections below and use TinyAuth with just a local username/password instead.
|
||||
::
|
||||
|
||||
## Installation
|
||||
|
||||
::file-tree
|
||||
@@ -103,6 +98,42 @@ Deploy the stack. The local interface is available at `http://yourserverip:3000`
|
||||
### Done !
|
||||
::
|
||||
|
||||
## Enabling Two-Factor Authentication
|
||||
TinyAuth can require a TOTP code from an authenticator app (Google Authenticator, Aegis...) alongside the local password, per user. This is a property of the user entry itself, not a toggle in the web UI.
|
||||
|
||||
::steps{level="3"}
|
||||
### Generate a TOTP secret
|
||||
|
||||
```bash [Terminal]
|
||||
sudo docker run -i -t --rm ghcr.io/tinyauthapp/tinyauth:v5 totp generate --interactive
|
||||
```
|
||||
|
||||
Enter the `username:hash` pair you generated during installation. TinyAuth prints a QR code to scan with your authenticator app, then outputs the updated login string as `username:hash:secret`.
|
||||
|
||||
::note
|
||||
|
||||
Both `docker run` and `docker exec` need the `-it` flags here: the command is interactive and renders the QR code in the terminal, which needs a TTY (and a wide enough window) to display correctly.
|
||||
::
|
||||
|
||||
### Update your environment variable
|
||||
|
||||
Replace that user's entry in `TINYAUTH_AUTH_USERS` with the new `username:hash:secret` string, then redeploy the stack.
|
||||
|
||||
::tip{icon=""}
|
||||
✨ __Tip:__ Verify the flow works before relying on it:
|
||||
|
||||
```bash [Terminal]
|
||||
sudo docker run -i -t --rm ghcr.io/tinyauthapp/tinyauth:v5 user verify --interactive
|
||||
```
|
||||
|
||||
It re-prompts for the username, password, and current 6-digit code.
|
||||
::
|
||||
|
||||
### Done !
|
||||
::
|
||||
|
||||
From now on, that user needs both their password and a valid code from their authenticator app to log in.
|
||||
|
||||
## Exposing TinyAuth with Swag
|
||||
TinyAuth needs its own subdomain: it's the page users land on before being forwarded to the app they actually want.
|
||||
|
||||
@@ -192,56 +223,6 @@ __If it fails:__ check your firewall rules.
|
||||
### Done !
|
||||
::
|
||||
|
||||
## Connecting TinyAuth to Pocket ID
|
||||
::steps{level="3"}
|
||||
### Register TinyAuth as an OIDC client
|
||||
|
||||
First, [register TinyAuth as an OIDC client in Pocket ID](/serveex/security/pocket-id#registering-an-oidc-client), using this callback URL:
|
||||
|
||||
```text
|
||||
https://tinyauth.mydomain.com/api/oauth/callback/pocketid
|
||||
```
|
||||
|
||||
### Add the Pocket ID provider
|
||||
|
||||
Copy the __Client ID__ and __Client Secret__ Pocket ID gives you, then edit TinyAuth's `.env` file:
|
||||
|
||||
```bash [Terminal]
|
||||
sudo nano /docker/tinyauth/.env
|
||||
```
|
||||
|
||||
Add the following:
|
||||
|
||||
```properties [.env]
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_NAME=Pocket ID
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_CLIENTID=
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_CLIENTSECRET=
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_AUTHURL=https://id.mydomain.com/authorize
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_TOKENURL=https://id.mydomain.com/api/oidc/token
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_USERINFOURL=https://id.mydomain.com/api/oidc/userinfo
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_REDIRECTURL=https://tinyauth.mydomain.com/api/oauth/callback/pocketid
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_SCOPES=openid email profile
|
||||
```
|
||||
|
||||
| Variable | Value |
|
||||
|----------|-------|
|
||||
| `CLIENTID`{lang=properties} | The client ID copied from Pocket ID |
|
||||
| `CLIENTSECRET`{lang=properties} | The client secret copied from Pocket ID |
|
||||
| `AUTHURL` / `TOKENURL` / `USERINFOURL`{lang=properties} | Pocket ID's public URL, with the paths shown above |
|
||||
|
||||
Press :kbd{value="Ctrl+O"}, then :kbd{value="Enter"} to save, and :kbd{value="Ctrl+X"} to exit.
|
||||
|
||||
### Redeploy the stack
|
||||
|
||||
Redeploy the TinyAuth stack. On your next visit to `https://tinyauth.mydomain.com`, you'll see a "Login with Pocket ID" option alongside the local login form.
|
||||
|
||||
::tip{icon=""}
|
||||
✨ To skip straight to Pocket ID and hide the local login form, add `TINYAUTH_OAUTH_AUTOREDIRECT=pocketid` to the same `.env` file.
|
||||
::
|
||||
|
||||
### Done !
|
||||
::
|
||||
|
||||
## Protecting an app via reverse proxy
|
||||
Swag doesn't ship a ready-made include file for TinyAuth, so we'll add the forward-auth check directly to the app's own `*.subdomain.conf`. We'll use Dockge as an example.
|
||||
|
||||
+53
-1
@@ -226,4 +226,56 @@ Save, then copy the generated __Client ID__ and __Client Secret__. You'll need t
|
||||
### Done !
|
||||
::
|
||||
|
||||
Pocket ID is ready to act as your OIDC provider. Head to the [TinyAuth guide](/serveex/security/tinyauth) to use it as a forward-auth login page for the rest of your apps.
|
||||
## Connecting Pocket ID to TinyAuth
|
||||
[TinyAuth](/serveex/security/tinyauth) can delegate its login to Pocket ID instead of (or alongside) its local username/password, so anyone visiting a protected app authenticates with a passkey and gets forwarded through.
|
||||
|
||||
::steps{level="3"}
|
||||
### Register TinyAuth as an OIDC client
|
||||
|
||||
[Register an OIDC client](#registering-an-oidc-client) named `TinyAuth`, using this callback URL:
|
||||
|
||||
```text
|
||||
https://tinyauth.mydomain.com/api/oauth/callback/pocketid
|
||||
```
|
||||
|
||||
### Add the Pocket ID provider in TinyAuth
|
||||
|
||||
Copy the __Client ID__ and __Client Secret__ Pocket ID gives you, then edit TinyAuth's `.env` file:
|
||||
|
||||
```bash [Terminal]
|
||||
sudo nano /docker/tinyauth/.env
|
||||
```
|
||||
|
||||
Add the following:
|
||||
|
||||
```properties [.env]
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_NAME=Pocket ID
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_CLIENTID=
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_CLIENTSECRET=
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_AUTHURL=https://id.mydomain.com/authorize
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_TOKENURL=https://id.mydomain.com/api/oidc/token
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_USERINFOURL=https://id.mydomain.com/api/oidc/userinfo
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_REDIRECTURL=https://tinyauth.mydomain.com/api/oauth/callback/pocketid
|
||||
TINYAUTH_OAUTH_PROVIDERS_POCKETID_SCOPES=openid email profile
|
||||
```
|
||||
|
||||
| Variable | Value |
|
||||
|----------|-------|
|
||||
| `CLIENTID`{lang=properties} | The client ID copied from Pocket ID |
|
||||
| `CLIENTSECRET`{lang=properties} | The client secret copied from Pocket ID |
|
||||
| `AUTHURL` / `TOKENURL` / `USERINFOURL`{lang=properties} | Pocket ID's public URL, with the paths shown above |
|
||||
|
||||
Press :kbd{value="Ctrl+O"}, then :kbd{value="Enter"} to save, and :kbd{value="Ctrl+X"} to exit.
|
||||
|
||||
### Redeploy the stack
|
||||
|
||||
Redeploy the TinyAuth stack. On your next visit to `https://tinyauth.mydomain.com`, you'll see a "Login with Pocket ID" option alongside the local login form.
|
||||
|
||||
::tip{icon=""}
|
||||
✨ To skip straight to Pocket ID and hide the local login form, add `TINYAUTH_OAUTH_AUTOREDIRECT=pocketid` to the same `.env` file.
|
||||
::
|
||||
|
||||
### Done !
|
||||
::
|
||||
|
||||
That's it! TinyAuth now offers passwordless login via Pocket ID for every app it protects.
|
||||
Reference in New Issue
Block a user