Add bilingual French/English support with Hugo multilingual config
Configure Hugo multilingual mode (fr default, en secondary) with Hextra's language-switch menu entry, and translate all existing content pages to English using Hugo's per-file language suffix convention (.en.md alongside .fr.md).
This commit is contained in:
602
content/blog/migration-gitlab-gitea/index.en.md
Normal file
602
content/blog/migration-gitlab-gitea/index.en.md
Normal file
@@ -0,0 +1,602 @@
|
||||
---
|
||||
title: "Self-Hosting and Hybrid Cloud: My Personal Infrastructure with Gitea and Scaleway"
|
||||
date: 2025-11-20
|
||||
authors:
|
||||
- name: Damien
|
||||
link: https://gitea.arnodo.fr/Damien
|
||||
tags:
|
||||
- Homelab
|
||||
- DevOps
|
||||
- Self-Hosting
|
||||
- Network Engineering
|
||||
---
|
||||
|
||||
A write-up on building my personal infrastructure: migrating from GitHub to self-hosted Gitea, and deploying ephemeral network labs on Scaleway. All powered by Proxmox and Wireguard.
|
||||
|
||||
<!--more-->
|
||||
|
||||
## Context and Motivations
|
||||
|
||||
As a network engineer working in automation and orchestration, I've always needed an environment to experiment and learn in. Until recently, I used GitHub for my code and ContainerLab locally/on AWS via [DevPod](/documentation/devpod/) for my network simulations.
|
||||
|
||||
But several needs emerged:
|
||||
|
||||
- **Learning**: Deploying and managing a full Git server with CI/CD
|
||||
- **Sovereignty**: Hosting my data in France (or at least in Europe), controlling my infrastructure
|
||||
- **Flexibility**: Being able to spin up network labs on demand without saturating my local machine
|
||||
- **Automation**: Scripting the complete provisioning of my environments
|
||||
|
||||
## The Overall Architecture
|
||||
|
||||

|
||||
|
||||
### Tech Stack
|
||||
|
||||
**Homelab**:
|
||||
- **Proxmox VE**: Hypervisor for VMs and LXC
|
||||
- **LXC Containers**: Gitea, runners, various services
|
||||
- **Ansible**: Configuration management and updates
|
||||
- **Grafana/Prometheus/Loki**: Monitoring and observability
|
||||
|
||||
**Public exposure**:
|
||||
- **Scaleway Dedibox**: Dedicated instance with a fixed IP
|
||||
- **Nginx Proxy Manager**: Reverse proxy with automatic SSL
|
||||
- **Wireguard VPN**: Secure tunnel between Scaleway and the homelab
|
||||
|
||||
**Scaleway Cloud**:
|
||||
- **Object Storage**: Hosting for the Hugo blog (S3-compatible)
|
||||
- **Instances**: Ephemeral network labs provisioned on demand
|
||||
- **Scaleway CLI**: Full automation
|
||||
|
||||
## Part 1: Migrating from GitHub to Self-Hosted Gitea
|
||||
|
||||
### Why Gitea?
|
||||
|
||||
[Gitea](https://gitea.io/) is a lightweight Git server, perfect for self-hosting:
|
||||
|
||||
- **Lightweight**: Ideal for an LXC on Proxmox
|
||||
- **GitHub Actions compatible**: Migrate workflows without rewriting them
|
||||
- **Full-featured**: Issues, PRs, CI/CD, webhooks
|
||||
- **Open-source**: Active community
|
||||
|
||||
### Deployment with Proxmox Helper Scripts
|
||||
|
||||
Rather than configuring everything manually, I use the excellent [Proxmox Helper Scripts](https://community-scripts.github.io/ProxmoxVE/), which automate the creation of preconfigured LXCs.
|
||||
|
||||
**Installing Gitea**:
|
||||
|
||||
```bash
|
||||
# On the Proxmox node, run the script
|
||||
bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/gitea.sh)"
|
||||
```
|
||||
|
||||
The script:
|
||||
- Creates a Debian 12 LXC
|
||||
- Installs Gitea and sqlite
|
||||
- Configures the systemd services
|
||||
- Sets up the environment with the correct permissions
|
||||
|
||||
**Post-installation configuration**:
|
||||
- Web access: `http://<IP_LXC>:3000`
|
||||
- Initial setup via the interface
|
||||
- Site URL: `https://gitea.arnodo.fr`
|
||||
|
||||
### Network Architecture: Wireguard + Nginx Proxy Manager
|
||||
|
||||
**The problem**: Gitea runs inside my homelab (private IP), but I want to access it from the Internet.
|
||||
|
||||
**The solution**:
|
||||
1. A **Scaleway Dedibox** with a fixed public IP and Nginx Proxy Manager
|
||||
2. A **Wireguard VPN** between the Dedibox and the homelab
|
||||
3. The reverse proxy routes `gitea.arnodo.fr` to the LXC's private IP through the tunnel
|
||||
|
||||
**Wireguard configuration (homelab side)**:
|
||||
|
||||
```ini
|
||||
[Interface]
|
||||
Address = 10.0.0.1/24
|
||||
PrivateKey = <private_key>
|
||||
ListenPort = 51820
|
||||
|
||||
[Peer]
|
||||
# Dedibox Scaleway
|
||||
PublicKey = <dedibox_public_key>
|
||||
AllowedIPs = 10.0.0.2/32
|
||||
Endpoint = <dedibox_public_ip>:51820
|
||||
PersistentKeepalive = 25
|
||||
```
|
||||
|
||||
**Nginx Proxy Manager**:
|
||||
- Proxy Host: `gitea.arnodo.fr`
|
||||
- Forward Hostname/IP: `10.0.0.x` (Gitea LXC IP over Wireguard)
|
||||
- Forward Port: `3000`
|
||||
- SSL: automatic Let's Encrypt
|
||||
- Websockets: Enabled
|
||||
|
||||
### Management with Ansible
|
||||
|
||||
To keep Gitea up to date and manage configurations, I use Ansible.
|
||||
|
||||
**Update playbook** (`update-gitea.yml`):
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Update Gitea
|
||||
hosts: gitea
|
||||
become: yes
|
||||
tasks:
|
||||
- name: Update apt cache
|
||||
apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Upgrade Gitea and system packages
|
||||
apt:
|
||||
upgrade: dist
|
||||
autoremove: yes
|
||||
autoclean: yes
|
||||
|
||||
- name: Restart Gitea service
|
||||
systemd:
|
||||
name: gitea
|
||||
state: restarted
|
||||
enabled: yes
|
||||
|
||||
- name: Check Gitea version
|
||||
command: gitea --version
|
||||
register: gitea_version
|
||||
|
||||
- debug:
|
||||
msg: "{{ gitea_version.stdout }}"
|
||||
```
|
||||
|
||||
**Execution**:
|
||||
|
||||
```bash
|
||||
ansible-playbook -i inventory.ini update-gitea.yml
|
||||
```
|
||||
|
||||
### Monitoring with Grafana
|
||||
|
||||
Gitea exposes Prometheus metrics (https://docs.gitea.com/administration/config-cheat-sheet#metrics-metrics)
|
||||
Configuration:
|
||||
|
||||
**In Gitea (`app.ini`)**:
|
||||
|
||||
```ini
|
||||
[metrics]
|
||||
ENABLED = true
|
||||
TOKEN = <secret_token>
|
||||
```
|
||||
|
||||
**Prometheus scrape config**:
|
||||
|
||||
```yaml
|
||||
scrape_configs:
|
||||
- job_name: 'gitea'
|
||||
metrics_path: /metrics
|
||||
bearer_token: '<secret_token>'
|
||||
static_configs:
|
||||
- targets: ['<gitea_lxc_ip>:3000']
|
||||
```
|
||||
|
||||
**Grafana dashboard** (https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-gitea/#gitea-integration-for-grafana-cloud):
|
||||
- Number of repositories, users
|
||||
- HTTP requests (rate, latency)
|
||||
- CI/CD runner status
|
||||
- LXC CPU/RAM usage
|
||||
|
||||
### Migrating Code from GitHub
|
||||
|
||||
Simple and fast:
|
||||
Use Gitea's import feature (Settings > New Migration > GitHub), which also migrates issues and releases.
|
||||
|
||||
### CI/CD: Deploying Hugo to Scaleway Object Storage
|
||||
|
||||
My Hugo blog deploys automatically to Scaleway Object Storage on every push.
|
||||
|
||||
**Installing the Gitea Runner** (https://docs.gitea.com/usage/actions/act-runner)
|
||||
|
||||
Create the system user for the runner:
|
||||
|
||||
```bash
|
||||
useradd -r -m -d /var/lib/gitea-runner -s /bin/bash gitea-runner
|
||||
```
|
||||
|
||||
Here's a small script that can help install the runner directly inside an LXC:
|
||||
|
||||
```bash
|
||||
sudo apt install -y jq curl tar # si pas déjà
|
||||
|
||||
LATEST=$(curl -s 'https://gitea.com/api/v1/repos/gitea/act_runner/releases' | jq -r '.[0].tag_name')
|
||||
echo "Latest act_runner: $LATEST"
|
||||
|
||||
# construire URL de binaire (nommage used: act_runner-<os>-<arch>)
|
||||
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
ARCH=$(uname -m)
|
||||
# Certains serveurs distribuent binaire sans tar; adapter si archive
|
||||
URL="https://gitea.com/gitea/act_runner/releases/download/${LATEST}/act_runner-${LATEST#v}-${OS}-${ARCH}"
|
||||
|
||||
# essayer télécharger binaire
|
||||
curl -fL "$URL" -o /tmp/act_runner || {
|
||||
echo "Téléchargement direct échoué — vérifier le nom exact sur la page release." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
sudo mv /tmp/act_runner /usr/local/bin/act_runner
|
||||
sudo chmod +x /usr/local/bin/act_runner
|
||||
```
|
||||
|
||||
and to verify:
|
||||
|
||||
```bash
|
||||
/usr/local/bin/act_runner --version
|
||||
```
|
||||
|
||||
>[!NOTE]
|
||||
> It's important to register the runner so it's recognized by Gitea.
|
||||
> For more information on configuring the runner, check the official Gitea documentation.
|
||||
> https://docs.gitea.io/fr/docs/usage/actions/runner/
|
||||
|
||||
**Gitea Actions workflow** (`.gitea/workflows/deploy.yml`):
|
||||
|
||||
```yaml
|
||||
name: Build and Deploy Hugo
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build_and_deploy:
|
||||
if: github.event.pull_request.merged == true
|
||||
name: Deploy Hugo Website
|
||||
runs-on: self-hosted
|
||||
|
||||
container:
|
||||
image: debian:bookworm-slim
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y git curl ca-certificates wget
|
||||
|
||||
- name: Install Hugo
|
||||
run: |
|
||||
wget https://github.com/gohugoio/hugo/releases/download/v0.152.2/hugo_extended_withdeploy_0.152.2_linux-amd64.deb -O /tmp/hugo.deb
|
||||
dpkg -i /tmp/hugo.deb
|
||||
|
||||
- name: Checkout code
|
||||
run: |
|
||||
git clone --recurse-submodules https://gitea.arnodo.fr/Damien/Notebook.git /tmp/workspace
|
||||
cd /tmp/workspace
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
- name: Build site
|
||||
run: /usr/local/bin/hugo
|
||||
working-directory: /tmp/workspace
|
||||
|
||||
- name: Deploy to Scaleway
|
||||
run: /usr/local/bin/hugo deploy --force --maxDeletes -1
|
||||
working-directory: /tmp/workspace
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.SCW_ACCESS_KEY }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCW_SECRET_KEY }}
|
||||
|
||||
```
|
||||
|
||||
**Hugo configuration** (`hugo.yaml`):
|
||||
|
||||
```yaml
|
||||
deployment:
|
||||
targets:
|
||||
- name: "notebook-arnodo-fr"
|
||||
URL: "s3://notebook-arnodo-fr?endpoint=https://s3.fr-par.scw.cloud®ion=fr-par"
|
||||
```
|
||||
|
||||
**Scaleway Object Storage configuration**:
|
||||
1. Create a `notebook-arnodo-fr` bucket
|
||||
2. Enable "Static Website Hosting" mode
|
||||
3. Generate API credentials (Access Key + Secret Key)
|
||||
4. Add them as secrets in Gitea (Settings > Secrets > Actions)
|
||||
|
||||
**Deployment**:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "New blog post"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
The workflow triggers automatically, Hugo builds the site, and deploys it to Scaleway Object Storage. The site is instantly available via the CDN.
|
||||
|
||||
## Part 2: Network Labs on Scaleway
|
||||
|
||||
### The Problem
|
||||
|
||||
Running ContainerLab with several Arista EOS instances locally is:
|
||||
- **Resource-hungry**: 4-8 GB RAM per cEOS container
|
||||
- **Local-only**: No access from outside
|
||||
- **Conflict-prone**: With other Docker/K8s services
|
||||
|
||||
### The Solution: On-Demand Scaleway Instances
|
||||
|
||||
**Concept**:
|
||||
- Spin up a Scaleway instance whenever I need a lab
|
||||
- Automatically install ContainerLab/the VPN via cloud-init
|
||||
- Destroy the instance after use
|
||||
- Billed by the hour (< €1 for a few hours of lab time)
|
||||
|
||||
### Automation Script: Scaleway CLI
|
||||
|
||||
I built a Bash script that manages the entire lifecycle of a lab instance.
|
||||
|
||||
**Features**:
|
||||
- **Creation**: Instance + Security Group (SSH from my IP only)
|
||||
- **Start/Stop**: Instance management
|
||||
- **Deletion**: Full cleanup (instance, volumes, IP, SG)
|
||||
|
||||
**Script structure** (`scaleway-instance.sh`):
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Configuration
|
||||
INSTANCE_NAME="NetLab"
|
||||
ZONE="fr-par-1"
|
||||
IMAGE="debian_bookworm"
|
||||
VOLUME_SIZE=20 # GB
|
||||
USER_DATA_FILE="user_data.txt"
|
||||
SECURITY_GROUP_NAME="${INSTANCE_NAME}-SG"
|
||||
|
||||
# Détecte l'IP publique actuelle
|
||||
get_public_ip() {
|
||||
curl -4 -s ifconfig.me
|
||||
}
|
||||
|
||||
# Crée un Security Group limitant SSH à l'IP publique
|
||||
create_or_update_security_group() {
|
||||
PUBLIC_IP=$(get_public_ip)
|
||||
# Crée le SG avec inbound SSH uniquement depuis PUBLIC_IP/32
|
||||
# ...
|
||||
}
|
||||
|
||||
# Actions : create, start, stop, delete
|
||||
case "$1" in
|
||||
start)
|
||||
# Démarre l'instance existante
|
||||
scw instance server start "$INSTANCE_ID" --wait
|
||||
;;
|
||||
stop)
|
||||
# Arrête l'instance
|
||||
scw instance server stop "$INSTANCE_ID" --wait
|
||||
;;
|
||||
delete)
|
||||
# Supprime instance + volumes + IP + SG
|
||||
scw instance server terminate "$INSTANCE_ID" --with-ip --with-block
|
||||
scw instance security-group delete "$SG_ID"
|
||||
;;
|
||||
*)
|
||||
# Crée une nouvelle instance
|
||||
create_instance "$1" # Type d'instance (DEV1-S, GP1-XS, ...)
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
### Cloud-Init: Automatic Configuration
|
||||
|
||||
The `user_data.txt` file contains the cloud-init instructions to automatically provision the instance.
|
||||
|
||||
**Example** (`user_data.txt`):
|
||||
|
||||
```yaml
|
||||
#cloud-config
|
||||
package_update: true
|
||||
package_upgrade: true
|
||||
|
||||
packages:
|
||||
- git
|
||||
- curl
|
||||
- docker.io
|
||||
- docker-compose
|
||||
|
||||
runcmd:
|
||||
# Installation de ContainerLab
|
||||
- bash -c "$(curl -sL https://get.containerlab.dev)"
|
||||
|
||||
# Clone d'un repo avec des topologies
|
||||
- git clone https://gitea.arnodo.fr/Damien/network-labs.git /root/labs
|
||||
|
||||
# Démarrage d'une topologie par défaut
|
||||
- cd /root/labs && containerlab deploy -t spine-leaf.clab.yml
|
||||
```
|
||||
|
||||
### Practical Usage
|
||||
|
||||
**Create a lab**:
|
||||
|
||||
```bash
|
||||
# Crée une instance DEV1-S avec 20 GB de stockage
|
||||
./scaleway-instance.sh DEV1-S 20
|
||||
|
||||
# Attend quelques minutes pour cloud-init
|
||||
# Récupère l'IP publique
|
||||
scw instance server list name=NetLab -o json | jq -r '.servers[0].public_ip.address'
|
||||
|
||||
# SSH vers l'instance
|
||||
ssh root@<IP_PUBLIQUE>
|
||||
|
||||
# ContainerLab est déjà lancé !
|
||||
containerlab inspect
|
||||
```
|
||||
|
||||
**Destroy the lab**:
|
||||
|
||||
```bash
|
||||
./scaleway-instance.sh delete
|
||||
```
|
||||
|
||||
### Raycast Integration
|
||||
|
||||
To make things even simpler, I created a Raycast script that lets me manage my instances directly from my Mac.
|
||||
|
||||
**Raycast script**:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# @raycast.schemaVersion 1
|
||||
# @raycast.title Scaleway Instance
|
||||
# @raycast.mode silent
|
||||
# @raycast.icon 🖥️
|
||||
# @raycast.argument1 { "type": "text", "placeholder": "Action or instance type" }
|
||||
# @raycast.argument2 { "type": "text", "placeholder": "Volume size", "optional": true }
|
||||
# @raycast.packageName NetLab
|
||||
|
||||
/path/to/scaleway-instance.sh "$1" "$2"
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
- `⌘ + Space` → "Scaleway Instance DEV1-S" → Creates the instance
|
||||
- `⌘ + Space` → "Scaleway Instance delete" → Deletes the instance
|
||||
|
||||
### Use Case: BGP/EVPN Lab with Arista
|
||||
|
||||
**ContainerLab topology** (`spine-leaf.clab.yml`):
|
||||
|
||||
```yaml
|
||||
name: evpn-lab
|
||||
|
||||
topology:
|
||||
nodes:
|
||||
spine1:
|
||||
kind: ceos
|
||||
image: ceos:latest
|
||||
spine2:
|
||||
kind: ceos
|
||||
image: ceos:latest
|
||||
leaf1:
|
||||
kind: ceos
|
||||
image: ceos:latest
|
||||
leaf2:
|
||||
kind: ceos
|
||||
image: ceos:latest
|
||||
|
||||
links:
|
||||
- endpoints: ["spine1:eth1", "leaf1:eth1"]
|
||||
- endpoints: ["spine1:eth2", "leaf2:eth1"]
|
||||
- endpoints: ["spine2:eth1", "leaf1:eth2"]
|
||||
- endpoints: ["spine2:eth2", "leaf2:eth2"]
|
||||
```
|
||||
|
||||
**Workflow**:
|
||||
1. Create the Scaleway instance
|
||||
2. Cloud-init deploys the topology
|
||||
3. Configure BGP/EVPN via Ansible or manually
|
||||
4. Test, experiment
|
||||
5. Destroy the instance
|
||||
|
||||
**Cost**: DEV1-S instance (2 vCPU, 2GB) = ~€0.015/hour. 4 hours of lab time = €0.06.
|
||||
|
||||
## Digital Sovereignty: Why It Matters
|
||||
|
||||
This hybrid infrastructure reflects a personal conviction about digital sovereignty.
|
||||
|
||||
### The Context
|
||||
|
||||
In my work as a network engineer, I see how important it is to be in control of your own infrastructure.
|
||||
|
||||
Choosing Scaleway (part of the Iliad group, French) and self-hosting Gitea means:
|
||||
- **Supporting the European tech ecosystem**
|
||||
- **Ensuring GDPR compliance**: French jurisdiction
|
||||
- **Reducing latency**: Datacenters in Paris
|
||||
- **Understanding**: Owning your entire chain end-to-end
|
||||
|
||||
### Learning by Doing
|
||||
|
||||
As a network professional (Arista, BGP/EVPN, automation), self-hosting lets me:
|
||||
- Apply Infrastructure as Code principles
|
||||
- Deeply understand CI/CD mechanics
|
||||
- Experiment without limits
|
||||
- Reproduce professional environments
|
||||
|
||||
## Assessment
|
||||
|
||||
### What Works Well
|
||||
|
||||
**Self-hosted Gitea**:
|
||||
- Very fast and stable
|
||||
- Proxmox Helper Scripts = 5-minute install
|
||||
- Ansible handles updates cleanly
|
||||
- Grafana monitors everything
|
||||
|
||||
**Wireguard + Nginx Proxy Manager**:
|
||||
- Secure exposure of the homelab
|
||||
- Excellent performance
|
||||
- Simple configuration
|
||||
|
||||
**Scaleway labs**:
|
||||
- Provisioning in 3 minutes
|
||||
- Total flexibility (size, duration)
|
||||
- Predictable costs (hourly billing)
|
||||
|
||||
**CI/CD Hugo → Scaleway Object Storage**:
|
||||
- Push-to-deploy in 2 minutes
|
||||
- Free (a few cents/month for storage)
|
||||
- Built-in CDN = ultra-fast site
|
||||
|
||||
### The Challenges
|
||||
|
||||
**Initial complexity**:
|
||||
- Wireguard + reverse proxy = learning curve
|
||||
- First Proxmox/LXC setup = a few hours
|
||||
|
||||
**Maintenance**:
|
||||
- Responsibility for updates (thankfully Ansible helps!)
|
||||
- Monitoring to set up yourself
|
||||
- Backups to automate
|
||||
|
||||
**Dependencies**:
|
||||
- If the Dedibox goes down, Gitea becomes unreachable
|
||||
- Solution: failover with a second Dedibox or VPS (coming soon)
|
||||
|
||||
## Next Steps
|
||||
|
||||
- **High availability**: A second Dedibox for failover
|
||||
- **Automatic backup**: Scripts to back up Gitea to Scaleway Object Storage
|
||||
- **More automation**: Terraform to provision the entire Scaleway infrastructure
|
||||
- **Arista MCP**: Building an MCP server to interact with network equipment via local LLMs
|
||||
- **Netbox integration**: Webhook from Netbox to a network validation pipeline
|
||||
|
||||
## Conclusion
|
||||
|
||||
This hybrid infrastructure (Proxmox homelab + Scaleway cloud) offers the best of both worlds:
|
||||
|
||||
- **Control**: Sensitive data (code, configurations) stays in the homelab
|
||||
- **Flexibility**: Cloud resources for one-off needs
|
||||
- **Learning**: A complete environment to experiment in
|
||||
- **Sovereignty**: Everything hosted in France, with European providers
|
||||
|
||||
Self-hosting isn't just about costs (spoiler: I pay about as much as before, if not more), but about learning, mastery, and a deep understanding of systems.
|
||||
|
||||
For a network or DevOps engineer, it's the ideal environment to reproduce professional use cases and build up skills.
|
||||
|
||||
## Resources
|
||||
|
||||
### Documentation
|
||||
- [Gitea](https://docs.gitea.io/)
|
||||
- [Proxmox Helper Scripts](https://community-scripts.github.io/ProxmoxVE/)
|
||||
- [Scaleway CLI](https://www.scaleway.com/en/cli/)
|
||||
- [ContainerLab](https://containerlab.dev/)
|
||||
- [Nginx Proxy Manager](https://nginxproxymanager.com/)
|
||||
|
||||
### My Repos
|
||||
- [Blog Hugo](https://gitea.arnodo.fr/Damien/blog)
|
||||
- [Network Labs](https://gitea.arnodo.fr/Damien/arista-evpn-vxlan-clab) (ContainerLab topologies)
|
||||
- [Scaleway Scripts](https://gitea.arnodo.fr/Damien/scaleway-automation)
|
||||
|
||||
### Community
|
||||
- [Proxmox Forum](https://forum.proxmox.com/)
|
||||
- [r/homelab](https://reddit.com/r/homelab)
|
||||
- [ContainerLab Slack](https://containerlab.dev/)
|
||||
Reference in New Issue
Block a user