'excurity" urls fixed + language switcher
This commit is contained in:
259
content/3.serveex/3.security/1.wireguard.md
Normal file
259
content/3.serveex/3.security/1.wireguard.md
Normal file
@ -0,0 +1,259 @@
|
||||
---
|
||||
navigation: true
|
||||
title: Wireguard
|
||||
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:
|
||||
|
||||
```console
|
||||
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
|
||||
---
|
||||
volumes:
|
||||
etc_wireguard:
|
||||
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:__ 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` | Domain name of the host | `mydomain.com` |
|
||||
| `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:
|
||||
|
||||
```shell
|
||||
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:
|
||||
|
||||
```console
|
||||
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
|
||||
::
|
||||
|
||||
```shell
|
||||
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:
|
||||
|
||||
```shell
|
||||
sudo cp ~/wg0.conf /docker/wireguard/config/wg_confs
|
||||
```
|
||||
::
|
||||
|
||||
Create `compose.yaml` in `/docker/wireguard`:
|
||||
|
||||
```shell
|
||||
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:
|
||||
|
||||
```shell
|
||||
cd /docker/wireguard
|
||||
sudo docker compose up -d
|
||||
```
|
||||
|
||||
::alert{type="info" icon="exclamation-circle"}
|
||||
:::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:
|
||||
|
||||

|
576
content/3.serveex/3.security/2.authentik.md
Normal file
576
content/3.serveex/3.security/2.authentik.md
Normal file
@ -0,0 +1,576 @@
|
||||
---
|
||||
navigation: true
|
||||
title: Authentik
|
||||
main:
|
||||
fluid: false
|
||||
---
|
||||
:ellipsis{left=0px width=40rem top=10rem blur=140px}
|
||||
# Authentik
|
||||
|
||||
::alert{type="info"}
|
||||
🎯 __Objectives:__
|
||||
- Install and expose Authentik
|
||||
- Configure Multi-Factor Authentication (MFA)
|
||||
- Protect a native app or an app behind a reverse proxy
|
||||
::
|
||||
|
||||
[Authentik](https://goauthentik.io) is a single sign-on (SSO) tool that allows you to log in once to all platforms compatible with OpenID. It can also secure access to your exposed services by injecting itself via SWAG into requests to those services.
|
||||
|
||||
For example, if you're exposing Dockge online at `dockge.mydomain.com`, you’ll first land on an Authentik login page when accessing it. If you've already authenticated with another Authentik-protected service, you won’t need to log in again. This allows you to authenticate only once per day for all protected services.
|
||||
|
||||
Authentik also supports multi-factor authentication, including TOTP (a code generated by the authentication app of your choice). Additionally, it allows login through Microsoft or Google accounts, provided you've configured one of those applications.
|
||||
|
||||
It's a great alternative to VPNs for securely exposing services, especially ones that lack MFA or login protection (e.g., the SWAG dashboard).
|
||||
|
||||
Authentik has [extensive documentation](https://docs.goauthentik.io/docs/installation/docker-compose) and [great tutorials from Cooptonian](https://www.youtube.com/@cooptonian). Here, we’ll cover the basics using Dockge as an example.
|
||||
|
||||
There are two main modes you should know:
|
||||
|
||||
- The first allows apps with native support for OpenID-compatible SSO to connect directly to Authentik. This is the preferred method, as the app itself decides what’s public and what’s protected.
|
||||
|
||||

|
||||
|
||||
- The second method injects Authentik authentication through SWAG before reaching the target service.
|
||||
|
||||

|
||||
|
||||
Both modes can be configured on a per-application basis.
|
||||
|
||||
## Installation
|
||||
---
|
||||
Folder structure:
|
||||
```console
|
||||
root
|
||||
└── docker
|
||||
└── authentik
|
||||
├── .env
|
||||
├── compose.yml
|
||||
├── media
|
||||
├── certs
|
||||
├── custom-template
|
||||
└── ssh
|
||||
```
|
||||
|
||||
Create the folders:
|
||||
|
||||
```shell
|
||||
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:
|
||||
|
||||
```shell
|
||||
sudo echo "PG_PASS=$(openssl rand 36 | base64)" >> .env
|
||||
sudo echo "AUTHENTIK_SECRET_KEY=$(openssl rand 60 | base64)" >> .env
|
||||
```
|
||||
|
||||
::alert{type="info"}
|
||||
:::list{type="info"}
|
||||
- To generate the keys, we created the folders ahead of deployment using Dockge. Dockge will prevent you from creating a stack with the same name in these folders unless a `compose.yml` file exists. So, create an empty `compose.yml` so it appears as an inactive stack:
|
||||
:::
|
||||
```shell
|
||||
sudo vi /docker/authentik/compose.yml
|
||||
::
|
||||
|
||||
Open Dockge and search for "authentik" in the inactive stacks.
|
||||
Name the stack `authentik` and paste the following configuration, replacing `{AUTHENTIK_TAG:-2024.2.3}`{lang=properties} with [the latest version of Authentik](https://version-2024-6.goauthentik.io/docs/releases).
|
||||
|
||||
```yaml
|
||||
---
|
||||
services:
|
||||
|
||||
postgresql:
|
||||
image: docker.io/library/postgres:12-alpine
|
||||
container_name: authentik-postgresql
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 5s
|
||||
volumes:
|
||||
- database:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
|
||||
POSTGRES_USER: ${PG_USER:-authentik}
|
||||
POSTGRES_DB: ${PG_DB:-authentik}
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
redis:
|
||||
image: docker.io/library/redis:alpine
|
||||
container_name: authentik-redis
|
||||
command: --save 60 1 --loglevel warning
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- redis-cli ping | grep PONG
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 3s
|
||||
volumes:
|
||||
- redis:/data
|
||||
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.2.3}
|
||||
container_name: authentik-server
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||
volumes:
|
||||
- ./media:/media
|
||||
- ./custom-templates:/templates
|
||||
- ./auth.css:/web/dist/custom.css
|
||||
- ./ssh:/authentik/.ssh
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- ${COMPOSE_PORT_HTTP:-9000}:9000
|
||||
- ${COMPOSE_PORT_HTTPS:-9443}:9443
|
||||
depends_on:
|
||||
- postgresql
|
||||
- redis
|
||||
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.2.3}
|
||||
container_name: authentik-worker
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||
# `user: root` and the docker socket volume are optional.
|
||||
# See more for the docker socket integration here:
|
||||
# https://goauthentik.io/docs/outposts/integrations/docker
|
||||
# Removing `user: root` also prevents the worker from fixing the permissions
|
||||
# on the mounted folders, so when removing this make sure the folders have the correct UID/GID
|
||||
# (1000:1000 by default)
|
||||
user: root
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./media:/media
|
||||
- ./certs:/certs
|
||||
- ./custom-templates:/templates
|
||||
- ./auth.css:/web/dist/custom.css
|
||||
- ./ssh:/authentik/.ssh
|
||||
env_file:
|
||||
- .env
|
||||
depends_on:
|
||||
- postgresql
|
||||
- redis
|
||||
|
||||
volumes:
|
||||
database:
|
||||
driver: local
|
||||
redis:
|
||||
driver: local
|
||||
```
|
||||
|
||||
In the `.env` file, the `PG_PASS` and `AUTHENTIK_SECRET_KEY` variables are already set.
|
||||
Deploy the stack.
|
||||
|
||||
You can then begin the initial setup by visiting:
|
||||
`http://yourserverip:9000/if/flow/initial-setup/`
|
||||
|
||||
::alert{type="warning"}
|
||||
:::list{type="warning"}
|
||||
- __Warning:__ It’s recommended to create a new admin account and **disable** the default `akadmin` account.
|
||||
:::
|
||||
::
|
||||
|
||||
## Exposing Authentik
|
||||
---
|
||||
To use Authentik outside your local network, you must expose it.
|
||||
|
||||
::alert{type="info"}
|
||||
📋 __Prerequisites:__ <br/><br/>
|
||||
We assume you have already created a subdomain like `auth.mydomain.com` in your [DNS zone](/general/dns), with a CNAME pointing to `mydomain.com`. Also, unless you're using [Cloudflare Zero Trust](/serveex/security/cloudflare), you must have already forwarded port `443` from your router to port `443` of your server in your [NAT rules](/general/nat).
|
||||
::
|
||||
|
||||
Open the `authentik-server.conf` file:
|
||||
|
||||
::alert{type="success"}
|
||||
✨ __Tip for those who dislike terminals:__
|
||||
You can use [File Browser](/serveex/files/file-browser) to navigate and edit files instead of using terminal commands.
|
||||
::
|
||||
|
||||
```shell
|
||||
sudo vi /docker/swag/config/nginx/authentik-server.conf
|
||||
```
|
||||
|
||||
Verify that the following variables are set correctly:
|
||||
|
||||
```nginx
|
||||
set $upstream_authentik authentik-server;
|
||||
proxy_pass http://$upstream_authentik:9000;
|
||||
```
|
||||
|
||||
If not, press `i` to enter edit mode, make the necessary changes, then save and exit by pressing `Esc` followed by `:x`.
|
||||
|
||||
Create the `auth.subdomain.conf` file:
|
||||
|
||||
```shell
|
||||
sudo vi /docker/swag/config/nginx/proxy-confs/auth.subdomain.conf
|
||||
```
|
||||
|
||||
Press `i` to enter edit mode and paste the following configuration:
|
||||
|
||||
```nginx
|
||||
## Version 2023/05/31
|
||||
# Ensure your authentik container is named authentik-server
|
||||
# Ensure your DNS has a CNAME for authentik
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
|
||||
server_name auth.*;
|
||||
|
||||
include /config/nginx/ssl.conf;
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
location / {
|
||||
include /config/nginx/proxy.conf;
|
||||
include /config/nginx/resolver.conf;
|
||||
set $upstream_app authentik-server;
|
||||
set $upstream_port 9000;
|
||||
set $upstream_proto http;
|
||||
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
|
||||
}
|
||||
|
||||
location ~ (/authentik)?/api {
|
||||
include /config/nginx/proxy.conf;
|
||||
include /config/nginx/resolver.conf;
|
||||
set $upstream_app authentik-server;
|
||||
set $upstream_port 9000;
|
||||
set $upstream_proto http;
|
||||
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Save and exit by pressing `Esc` then `:x`.
|
||||
|
||||
Go to Dockge, and edit the SWAG compose file to add the Authentik network:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
swag:
|
||||
container_name: # ...
|
||||
# ...
|
||||
networks: # Attach the container to the custom network
|
||||
# ...
|
||||
- authentik # Name of the network declared in the stack
|
||||
|
||||
networks: # Define the custom network
|
||||
# ...
|
||||
authentik: # Name of the network declared in the stack
|
||||
name: authentik_default # Actual name of the external network
|
||||
external: true # Indicates it's an external network
|
||||
```
|
||||
|
||||
Restart the stack and wait for SWAG to be fully operational.
|
||||
|
||||
Done! You can now access Authentik via `https://auth.mydomain.com`
|
||||
|
||||
## Enable Multifactor Authentication
|
||||
---
|
||||
The main value of Authentik is using multifactor authentication for all protected apps.
|
||||
|
||||
- Go to `https://auth.mydomain.com`
|
||||
- Log in
|
||||
- Go to _Settings_
|
||||
- Click the _MFA_ section
|
||||
- Click _Register_
|
||||
- Choose a method like _TOTP device_ (you'll need an authenticator app like Google Authenticator)
|
||||
- Follow the steps
|
||||
|
||||
You’ll now be prompted to enter a one-time code at every login.
|
||||
|
||||
## Protecting a Native App
|
||||
---
|
||||
Authentik is natively compatible with several applications. You can find the list and [support here](https://docs.goauthentik.io/integrations/services/).
|
||||
|
||||
## Protecting an App via Reverse Proxy
|
||||
---
|
||||
SWAG lets you insert Authentik’s login page between a request and access to your service. To do this:
|
||||
|
||||
- Configure the authentication provider in Authentik.
|
||||
- Edit the domain proxy file so SWAG can intercept the request.
|
||||
|
||||
Why do this when Dockge already has authentication? Because Dockge uses weak HTTP authentication. With Authentik, you get strong MFA authentication and automatic login to all apps protected by Authentik. This secures access to Dockge and other apps without needing a VPN.
|
||||
|
||||
### Configuring Authentik
|
||||
|
||||
- Go to Authentik
|
||||
- Open the admin panel
|
||||
- Select _Applications_ then _Create with wizard_
|
||||
- Fill in the fields as shown:
|
||||
|
||||

|
||||
|
||||
- At the next step, choose "Forward authentication (single application)" and configure it as shown (flows are important):
|
||||
|
||||

|
||||
|
||||
- Next, go to the _Outposts_ menu on the left and edit _authentik Embedded Outpost_:
|
||||
|
||||

|
||||
|
||||
- Add the `dockge` application by moving it to the right column and save.
|
||||
|
||||
### Configuring SWAG
|
||||
|
||||
Edit the file `dockge.mydomain.com`:
|
||||
|
||||
```shell
|
||||
sudo vi /docker/swag/config/nginx/proxy-confs/dockge.subdomain.conf
|
||||
```
|
||||
|
||||
Press `i` to enter edit mode and uncomment the two lines `#include /config/nginx/authentik-server.conf;`
|
||||
|
||||
Press `Esc`, type `:x`, and press `Enter` to save and exit.
|
||||
|
||||
Done! Now when accessing `https://dockge.mydomain.com`, you’ll be redirected to the Authentik login screen.
|
||||
|
||||
::alert{type="success"}
|
||||
✨ __Tip:__ In Dockge's settings, you can disable Dockge's authentication to avoid double login. **Warning**: this means if the port is open on your local network, there will be no authentication at all.
|
||||
::
|
||||
|
||||
::alert{type="info"}
|
||||
:::list{type="info"}
|
||||
- Repeat this process for each app you want to protect (unless it has native integration with Authentik).
|
||||
:::
|
||||
::
|
||||
|
||||
Your new architecture looks like this:
|
||||
|
||||

|
||||
|
||||
## Protecting a Remote Server Service
|
||||
---
|
||||
For a [native application](/serveex/security/authentik/#protecting-a-native-app) (via OAuth 2.0 or other), nothing changes.
|
||||
|
||||
For a non-native app behind a reverse proxy, you must deploy an __Outpost__. An Outpost is a container acting as a local proxy — it's the target of your app's auth requests and the only one authorized to communicate with your Authentik API.
|
||||
|
||||
::alert{type="info"}
|
||||
Prerequisites:
|
||||
- Install [Docker](/serveex/core/docker) on the remote server hosting the service.
|
||||
- If the app has no native integration, use a compatible reverse proxy. We will use [SWAG](/serveex/core/swag) here.
|
||||
::
|
||||
|
||||
This container will forward requests to your main [Authentik](/serveex/security/authentik#authentik) instance over the internet (or your local network). The server will perform checks and respond to the Outpost, which will allow or block access accordingly.
|
||||
|
||||

|
||||
|
||||
### Configuring Authentik
|
||||
|
||||
Create your [providers and applications](/serveex/security/authentik/#protecting-a-native-app) as shown earlier.
|
||||
|
||||
Then, in the admin panel, go to _Applications > Outposts_, and create a new outpost.
|
||||
|
||||
Fill in as follows:
|
||||
|
||||
| Field | Value |
|
||||
|----------------|------------------------------------------------------------------------|
|
||||
| `Name` | Your preferred name |
|
||||
| `Type` | `Proxy` |
|
||||
| `Integration` | Leave empty |
|
||||
| `Applications` | Select the applications you previously created |
|
||||
|
||||
In the `Advanced settings` section, clear the existing content and enter:
|
||||
|
||||
```yaml
|
||||
log_level: info
|
||||
docker_labels: null
|
||||
authentik_host: https://your_authentik_server_domain/
|
||||
object_naming_template: ak-outpost-%(name)s
|
||||
authentik_host_insecure: false
|
||||
container_image:
|
||||
docker_network: null
|
||||
docker_map_ports: true
|
||||
docker_labels: null
|
||||
```
|
||||
|
||||
Save and exit.
|
||||
|
||||
On the list of created outposts, locate the new one and click _Show details_ at the end of the line. Carefully copy the access token.
|
||||
|
||||
|
||||
### Configuring the Remote Machine
|
||||
|
||||
We assume you’ve already installed [Docker](/serveex/core/docker) and [SWAG](/serveex/core/swag) on this remote machine.
|
||||
|
||||
On your remote machine, use [Dockge](/serveex/core/docker/#installer-dockge-pour-gérer-et-déployer-les-conteneurs) to create a stack named `authentik-outpost`.
|
||||
|
||||
If you haven’t installed [Dockge](/serveex/core/docker/#installer-dockge-pour-gérer-et-déployer-les-conteneurs), create a folder `/docker/authentik-outpost`, or directly via command line:
|
||||
|
||||
```shell
|
||||
sudo mkdir -P /docker/authentik-outpost
|
||||
```
|
||||
|
||||
::alert{type="success"}
|
||||
✨ __Tip for terminal-averse users:__
|
||||
You can use [File Browser](/serveex/files/file-browser) to navigate and edit your files instead of using terminal commands.
|
||||
::
|
||||
|
||||
Create the `compose.yaml` file or paste the configuration directly into Dockge if installed.
|
||||
|
||||
Via command line:
|
||||
|
||||
```shell
|
||||
sudo vi /docker/authentik-outpost/compose.yaml
|
||||
```
|
||||
Enter edit mode by pressing `i` and paste the following configuration, updating the version in `{AUTHENTIK_TAG:proxy:2024.2.3}`{lang=properties} to match your Authentik server version.
|
||||
|
||||
```yaml
|
||||
version: "3.5"
|
||||
services:
|
||||
authentik_proxy:
|
||||
container_name: authentik-outpost
|
||||
image: ghcr.io/goauthentik/proxy:2024.2.3
|
||||
# Optionally specify which networks the container should be
|
||||
# might be needed to reach the core authentik server
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 9000:9000
|
||||
- 9443:9443
|
||||
environment:
|
||||
AUTHENTIK_HOST: ${HOST}
|
||||
AUTHENTIK_INSECURE: "false"
|
||||
AUTHENTIK_TOKEN: ${TOKEN}
|
||||
```
|
||||
|
||||
Go to the SWAG stack on the remote machine (or edit directly using Dockge) and add the authentik-outpost network in the configuration file like this (see `networks` section):
|
||||
|
||||
```shell
|
||||
sudo vi /docker/swag/compose.yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
services:
|
||||
swag:
|
||||
container_name: #...
|
||||
# ...
|
||||
networks: # Attach the container to the custom network
|
||||
- authentik-outpost # Network name as declared in the stack
|
||||
|
||||
networks: # Define the custom network
|
||||
#...
|
||||
authentik-outpost: # Name of the network declared in the stack
|
||||
name: authentik-outpost_default # Actual name of the external network
|
||||
external: true # Marks it as an external network
|
||||
```
|
||||
|
||||
Press `Esc`, then type `:x` and press `Enter` to save and exit.
|
||||
|
||||
::alert{type="info"}
|
||||
:::list{type="info"}
|
||||
- We assume the Dockge network name is `authentik-outpost_default`.
|
||||
:::
|
||||
::
|
||||
|
||||
If using [Dockge](/serveex/core/docker/#installer-dockge-pour-gérer-et-déployer-les-conteneurs), restart SWAG.
|
||||
|
||||
Otherwise, via terminal:
|
||||
|
||||
```shell
|
||||
cd /docker/swag/
|
||||
sudo docker compose up -d
|
||||
```
|
||||
|
||||
Create (or fill using Dockge) the `.env` file in the `authentik-outpost` directory:
|
||||
|
||||
Via command line:
|
||||
|
||||
```shell
|
||||
sudo vi /docker/authentik-outpost/.env
|
||||
```
|
||||
|
||||
Enter edit mode with `i` and paste the following configuration:
|
||||
|
||||
```properties
|
||||
HOST=
|
||||
TOKEN=
|
||||
```
|
||||
|
||||
Fill in the values:
|
||||
|
||||
| Variable | Value | Example |
|
||||
|----------|-------|---------|
|
||||
| `HOST`{lang=properties} | The URL of your Authentik server | `https://auth.domain.com` |
|
||||
| `TOKEN`{lang=properties} | The previously copied access token | `Q2pVEqsTNRkJSO9SkJzU3KZ2` |
|
||||
|
||||
Press `Esc`, then type `:x` and press `Enter` to save and exit.
|
||||
|
||||
If using Dockge, deploy the stack.
|
||||
|
||||
Otherwise, via terminal:
|
||||
|
||||
```shell
|
||||
cd /docker/authentik-outpost/
|
||||
sudo docker compose up -d
|
||||
```
|
||||
|
||||
The container is now running. You can verify its status from your Authentik instance admin panel under _Applications > Outposts_.
|
||||
|
||||
Now, let’s configure SWAG.
|
||||
|
||||
Open the `authentik-server.conf` file:
|
||||
|
||||
```shell
|
||||
sudo vi /docker/swag/config/nginx/authentik-server.conf
|
||||
```
|
||||
|
||||
In the file, press `i` to enter edit mode and change `authentik-server` to `authentik-outpost` as shown:
|
||||
|
||||
```nginx
|
||||
set $upstream_authentik authentik-outpost;
|
||||
proxy_pass http://$upstream_authentik:9000;
|
||||
```
|
||||
|
||||
Save and exit with `Esc`, then `:x` and `Enter`.
|
||||
|
||||
Then configure the applications to protect as you did on your main server, whether they are [native](/serveex/security/authentik/#protecting-a-native-app) or protected via [reverse proxy](/serveex/security/authentik#protecting-an-app-via-reverse-proxy).
|
||||
|
||||
## Migrating an Authentik Database
|
||||
---
|
||||
On the source machine, dump the database:
|
||||
|
||||
```shell
|
||||
sudo docker exec authentik-postgres pg_dump -U authentik -F t authentik > /path/to/mydb.tar
|
||||
```
|
||||
|
||||
Then transfer it to the target machine. On the target machine, copy the file into the Docker container:
|
||||
|
||||
```shell
|
||||
cp /path/to/mydb.tar authentik-postgres:/path/to/wherever
|
||||
```
|
||||
|
||||
(Optional) Purge existing tables:
|
||||
|
||||
```shell
|
||||
sudo docker exec -i authentik-postgres psql -U authentik -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'authentik' AND pid <> pg_backend_pid();" && sudo docker exec -i authentik-postgres psql -U authentik -d postgres -c "DROP DATABASE IF EXISTS authentik;" && sudo docker exec -i authentik-postgres psql -U authentik -d postgres -c "CREATE DATABASE authentik;"
|
||||
```
|
||||
|
||||
Restore the database:
|
||||
|
||||
```shell
|
||||
sudo docker exec authentik-postgresql pg_restore -U authentik -d authentik /path/to/wherever/mydb.tar
|
||||
```
|
263
content/3.serveex/3.security/3.cloudflare.md
Normal file
263
content/3.serveex/3.security/3.cloudflare.md
Normal file
@ -0,0 +1,263 @@
|
||||
---
|
||||
navigation: true
|
||||
title: Cloudflare Zero Trust
|
||||
main:
|
||||
fluid: false
|
||||
---
|
||||
:ellipsis{left=0px width=40rem top=10rem blur=140px}
|
||||
# Cloudflare Zero Trust
|
||||
|
||||
::alert{type="info"}
|
||||
🎯 __Goals:__
|
||||
- Understand the concept of Cloudflare Tunnels
|
||||
- Configure your Cloudflare account
|
||||
- Configure SWAG
|
||||
- Manage multiple tunnels
|
||||
::
|
||||
|
||||

|
||||
|
||||
## Introduction
|
||||
---
|
||||
The _Zero Trust_ architecture is the practice of designing systems based on the principle of __"never trust, always verify"__, as opposed to the traditional principle of __"trust, but verify"__. This concept has become increasingly popular recently due to the growing number of attacks targeting user data. It’s a broad concept, but we’ll focus on how to apply _Zero Trust_ to the web services we host.
|
||||
|
||||
_Cloudflare tunnels_ offer a simple way to implement _Zero Trust_, using [SWAG](/serveex/core/swag) and [Authentik](/serveex/security/authentik).
|
||||
|
||||
Simply put, Cloudflare Tunnels allow you to:
|
||||
|
||||
- Hide your server’s IP (and your home IP if it's self-hosted)
|
||||
- Authenticate traffic
|
||||
- Benefit from Cloudflare protections (DDoS attacks, blacklists, malicious requests, etc.)
|
||||
- Use Cloudflare's CDN to cache and speed up your websites
|
||||
- Avoid opening router ports for services exposed by SWAG
|
||||
|
||||
Here we’ll explain how to integrate SWAG with Cloudflare tunnels.
|
||||
|
||||
::alert{type="warning"}
|
||||
:::list{type="warning"}
|
||||
- __Warning:__
|
||||
:::
|
||||
- Do not use Cloudflare tunnels to expose a mail server
|
||||
- Do not use Cloudflare tunnels to expose a video service like Plex (if you followed [this guide](/serveex/media/plex), Plex is not exposed, so it’s fine)
|
||||
- Do not use Cloudflare tunnels for the BitTorrent protocol (if you followed [this guide](/serveex/media/qbittorrent), everything is fine)
|
||||
::
|
||||
|
||||
## Cloudflare Configuration
|
||||
---
|
||||
### DNS Zone
|
||||
|
||||
First, you need to set Cloudflare as your [DNS zone](/general/dns) manager. If you bought your domain from Cloudflare, that’s already done. Otherwise, check with your registrar how to add external DNS servers. Cloudflare provides [step-by-step documentation](https://developers.cloudflare.com/dns/zone-setups/full-setup/setup/) on how to configure a DNS Zone, whether your domain is external or registered with Cloudflare.
|
||||
|
||||
If you only have one server to protect behind Cloudflare, you can delete all existing DNS records. By default, your domain and all its subdomains will be redirected to the tunnel.
|
||||
|
||||
If you have subdomains pointing to other servers, you can still define them in the DNS zone using A records.
|
||||
|
||||
If you have several servers and tunnels under one domain, [see here](http://192.168.7.80:8005/serveex/cloudflare/#gerer-plusieurs-tunnels-pour-plusieurs-serveurs).
|
||||
|
||||
### API Key
|
||||
|
||||
Start by creating a new Cloudflare API token and retrieving your zone and account IDs.
|
||||
|
||||
On your Cloudflare dashboard, on your domain overview page, you’ll see the `zone` and `account` IDs at the bottom right. Save both securely.
|
||||
|
||||

|
||||
|
||||
Just below that is a link titled _Get your API token_. Click it. The token scope must include `Zone:DNS:Edit` and `Account:Cloudflare Tunnel:Edit`. Your page should look like the screenshot below.
|
||||
|
||||

|
||||
|
||||
Once created, your token will only be shown once. Save it securely, as it cannot be viewed again later.
|
||||
|
||||
### Cloudflare Zero Trust
|
||||
|
||||
You must register for _Cloudflare Teams_ to access the _Zero Trust_ dashboard that manages tunnels and access policies. This is a premium service, but there’s a free plan for up to 50 users—perfect for a home lab. Keep in mind that a valid credit card is required to register, but the free plan incurs no charges.
|
||||
|
||||
Register [via this link](https://dash.teams.cloudflare.com/).
|
||||
|
||||
## SWAG Configuration
|
||||
---
|
||||
::alert{type="info"}
|
||||
:::list{type="info"}
|
||||
- This guide assumes you own `mondomaine.fr` and that its DNS is correctly pointing to Cloudflare, as described above.
|
||||
:::
|
||||
::
|
||||
|
||||
SWAG supports two Docker Mods:
|
||||
|
||||
- __Cloudflared__, the container used to create and manage tunnels
|
||||
- __Cloudflared Real IP__, which allows SWAG to receive the true source IP of incoming requests instead of Docker’s internal IP (important for IP geolocation mods like DBIP).
|
||||
|
||||
These two mods, merged into the SWAG container, require some configuration.
|
||||
|
||||
### Tunnel Configuration
|
||||
|
||||
Create a file `tunnelconfig.yml` to reference in your SWAG `compose.yaml`.
|
||||
|
||||
::alert{type="success"}
|
||||
✨ __Tip:__ Use [File Browser](/serveex/files/file-browser) to navigate and edit files instead of using the terminal.
|
||||
::
|
||||
|
||||
```shell
|
||||
sudo vi /docker/swag/config/tunnelconfig.yml
|
||||
```
|
||||
|
||||
Press `i` to enter insert mode and paste:
|
||||
|
||||
```yaml
|
||||
ingress:
|
||||
- hostname: mondomaine.fr
|
||||
service: https://mondomaine.fr
|
||||
- hostname: "*.mondomaine.fr"
|
||||
service: https://mondomaine.fr
|
||||
- service: http_status:404
|
||||
```
|
||||
|
||||
Press `Esc`, then save and exit with `:x` and `Enter`.
|
||||
|
||||
### Cloudflare Real IP Configuration
|
||||
|
||||
Now configure _Cloudflare Real IP_.
|
||||
|
||||
Open the `nginx.conf` file:
|
||||
|
||||
```shell
|
||||
sudo vi /docker/swag/config/nginx/nginx.conf
|
||||
```
|
||||
|
||||
Press `i` and add the following at the end of the `http` section:
|
||||
|
||||
```nginx
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
include /config/nginx/cf_real-ip.conf;
|
||||
set_real_ip_from 127.0.0.1;
|
||||
```
|
||||
|
||||
Save and exit with `:x`.
|
||||
|
||||
### Docker Compose
|
||||
|
||||
In Dockge, edit your SWAG stack with this:
|
||||
|
||||
```yaml
|
||||
---
|
||||
services:
|
||||
swag:
|
||||
image: lscr.io/linuxserver/swag:latest
|
||||
container_name: swag
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- DOCKER_MODS=linuxserver/mods:swag-dbip|linuxserver/mods:swag-dashboard|linuxserver/mods:swag-auto-reload|linuxserver/mods:universal-cloudflared|linuxserver/mods:swag-cloudflare-real-ip
|
||||
- PUID=${PUID}
|
||||
- PGID=${PGID}
|
||||
- TZ=Europe/Paris
|
||||
- URL=${DOMAIN}
|
||||
- SUBDOMAINS=wildcard
|
||||
- VALIDATION=dns
|
||||
- DNSPLUGIN=${PLUGIN}
|
||||
- EMAIL=${EMAIL}
|
||||
- CF_ZONE_ID=${ZONE_ID}
|
||||
- CF_ACCOUNT_ID=${ACCOUNT_ID}
|
||||
- CF_API_TOKEN=${API_TOKEN}
|
||||
- CF_TUNNEL_NAME=${TUNNEL_NAME}
|
||||
- CF_TUNNEL_PASSWORD=${TUNNEL_PW}
|
||||
- FILE__CF_TUNNEL_CONFIG=/config/tunnelconfig.yml
|
||||
extra_hosts:
|
||||
- ${DOMAIN}:127.0.0.1
|
||||
ports:
|
||||
- 81:81
|
||||
volumes:
|
||||
- /docker/swag/config:/config
|
||||
- /docker/swag/config/fail2ban/fail2ban.sqlite3:/dashboard/fail2ban.sqlite3:ro
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
::alert{type="success"}
|
||||
✨ __Tip:__ Add a Watchtower label to automate updates:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- com.centurylinklabs.watchtower.enable=true
|
||||
```
|
||||
::
|
||||
|
||||
Fill in your `.env` file:
|
||||
|
||||
```properties
|
||||
PUID=
|
||||
PGID=
|
||||
DOMAIN=
|
||||
PLUGIN=
|
||||
EMAIL=
|
||||
ZONE_ID=
|
||||
ACCOUNT_ID=
|
||||
API_TOKEN=
|
||||
TUNNEL_NAME=
|
||||
TUNNEL_PW=
|
||||
```
|
||||
|
||||
| Variable | Value | Example |
|
||||
|----------------|-------------------------------------------------------------|--------------------------------|
|
||||
| `PUID` | User ID (`id username`) | `1000` |
|
||||
| `GUID` | Group ID (`id username`) | `1000` |
|
||||
| `DOMAIN` | Your reserved domain | `mondomaine.fr` |
|
||||
| `PLUGIN` | DNS provider (also configure `cloudflare.ini`) | `cloudflare` |
|
||||
| `EMAIL` | Email for the certificate | `you@email.com` |
|
||||
| `ZONE_ID` | Cloudflare Zone ID | `aNhcz1l3JfWbFZo2XMpzQlP2iOqk` |
|
||||
| `ACCOUNT_ID` | Cloudflare Account ID | `buKsjNHLyzKMM1qYnzOy4s7SHfly` |
|
||||
| `API_TOKEN` | API token | `53ydYus9TFFk1DOXNdP87iIcJtQjoW` |
|
||||
| `TUNNEL_NAME` | Tunnel name | `my_tunnel` |
|
||||
| `TUNNEL_PW` | Strong, random password | `iSzKRmP4VbnlsMvdSdgBEJiJi` |
|
||||
|
||||
Once done, deploy the stack. Check the logs—you should reach `server ready`.
|
||||
|
||||
Then confirm your tunnel appears under _Networks > Tunnels_ in [Cloudflare Zero Trust](https://one.dash.cloudflare.com/). By default, all subdomains will be routed through the tunnel—no need to define them [in your DNS zone](/general/dns).
|
||||
|
||||
::alert{type="success"}
|
||||
✨ __Tip:__ If you want to expose a service without a tunnel, just define an A record [in your DNS zone](/general/dns). If resolution fails, disable the proxy function for that record—e.g., for `sub.mondomaine.fr`.
|
||||

|
||||
::
|
||||
|
||||
## Managing Multiple Tunnels for Multiple Servers
|
||||
---
|
||||
By default, all subdomains of your domain are routed through the single tunnel. But if you have a second server, just change the tunnel name in that SWAG instance.
|
||||
|
||||
In your DNS zone, redirect subdomains to the correct tunnel.
|
||||
|
||||
Go to _Networks > Tunnels_ in [Cloudflare Zero Trust](https://one.dash.cloudflare.com/).
|
||||
|
||||
Note the tunnel IDs:
|
||||
|
||||

|
||||
|
||||
Then in the [Cloudflare DNS dashboard](https://dash.cloudflare.com/), click your domain name.
|
||||
|
||||
Click `Add Record` and add these two CNAME records (include `.cfargotunnel.com`):
|
||||
|
||||
| Type | Name | Target |
|
||||
|---------|--------------|----------------------------------------|
|
||||
| `CNAME` | `subdomain1` | `yourtunnelid1.cfargotunnel.com` |
|
||||
| `CNAME` | `subdomain2` | `yourtunnelid2.cfargotunnel.com` |
|
||||
|
||||
If you have many subdomains, point them to the above reference subdomains.
|
||||
|
||||
This way, if a tunnel ID changes, you only update one DNS record.
|
||||
|
||||
Example:
|
||||
|
||||
- `sub1` and `sub2` also point to the server behind `subdomain1`:
|
||||
|
||||
| Type | Name | Target |
|
||||
|---------|--------|---------------|
|
||||
| `CNAME` | `sub1` | `subdomain1` |
|
||||
| `CNAME` | `sub2` | `subdomain1` |
|
||||
|
||||
- `sub3` and `sub4` point to the server behind `subdomain2`:
|
||||
|
||||
| Type | Name | Target |
|
||||
|---------|--------|---------------|
|
||||
| `CNAME` | `sub3` | `subdomain2` |
|
||||
| `CNAME` | `sub4` | `subdomain2` |
|
1
content/3.serveex/3.security/_dir.yml
Normal file
1
content/3.serveex/3.security/_dir.yml
Normal file
@ -0,0 +1 @@
|
||||
navigation.title: Security
|
Reference in New Issue
Block a user