Technical Report: Secure Infrastructure & Immich Deployment on Proxmox

Project Overview: Implementation of a high-security media server environment. This project focuses on transforming a Proxmox host into a NAT gateway and deploying a micro-services stack (Immich) using Docker, protected by LUKS encryption and advanced volume management.


1. Network & Routing Configuration

Our architecture isolates the application layer from the public network through a dual-bridge system, managed by kernel-level routing and a custom firewall.

Phase A: Bridge Definition

We configured /etc/network/interfaces to separate the WAN (School network) from the internal LAN (Container network):

Bash

auto lo
iface lo inet loopback

auto eno1
iface eno1 inet manual

auto vmbr0
iface vmbr0 inet static
    address 10.0.24.105/24
    gateway 10.0.24.254
    bridge-ports eno1
    bridge-stp off
    bridge-fd 0

auto vmbr1
iface vmbr1 inet static
    address 192.168.1.254/24
    bridge-ports none
    bridge-stp off
    bridge-fd 0

Phase B: Kernel Routing & Optimization

To allow traffic to flow between bridges and harden the host, we applied parameters in /etc/sysctl.d/99-firewall.conf:

Bash

net.ipv4.ip_forward = 1
net.ipv6.conf.default.forwarding = 1
net.ipv6.conf.all.forwarding = 1
net.ipv4.conf.default.proxy_arp = 0
net.ipv4.conf.all.rp_filter = 1
kernel.sysrq = 1
net.ipv4.conf.default.send_redirects = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.icmp_echo_ignore_all = 1
vm.swappiness = 0

Phase C: Firewall & NAT Logic (nftables)

The script /etc/firewall_Host.sh defines the security rules, using nftables for high-performance filtering and dynamic NAT rules.

Bash

wan_if='vmbr0'
lxc_if='vmbr1'

iptables -F
iptables -t nat -F
nft flush ruleset

nft -f - <<EOF
table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        iif "lo" accept
        ct state established,related accept
        iifname "$lxc_if" accept
        iifname "$wan_if" tcp dport { 80, 443, 8006, 22224, 9221 } accept
        iifname "$wan_if" udp dport 53 accept
    }
    chain forward {
        type filter hook forward priority 0; policy accept;
        ct state established,related accept
    }
    chain output {
        type filter hook output priority 0; policy accept;
    }
}
table ip nat {
    chain prerouting {
        type nat hook prerouting priority -100; policy accept;
        $(grep "PREROUTING" /etc/init.d/MyNatRules.config | sed 's/iptables -t nat -A PREROUTING -i/iif/g' | sed 's/-p tcp //g' | sed 's/--dport/tcp dport/g')
    }
    chain postrouting {
        type nat hook postrouting priority 100; policy accept;
        oif "$wan_if" masquerade
    }
}
EOF

Phase D: Persistence (Systemd)

To ensure rules persist after a reboot, we created a service in /etc/systemd/system/firewall.service:

Ini, TOML

[Unit]
Description=Script de Firewall et NAT pour les CT LXC
After=network.target

[Service]
Type=oneshot
ExecStart=/bin/bash /etc/firewall_Host.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

2. Immich Deployment via Docker

Inside an LXC container (ID 141), we deployed the Immich stack. By modifying the .env file, we redirected media storage to a secure mount point.

Bash

curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh
mkdir -p ~/immich-app && cd ~/immich-app
wget https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget https://github.com/immich-app/immich/releases/latest/download/example.env -O .env
sed -i 's|UPLOAD_LOCATION=./library|UPLOAD_LOCATION=/mnt/immich_data|' .env
docker compose up -d

3. Volume Management, Encryption & Privileges

This phase focuses on creating a « Zero-Knowledge » storage layer where data is encrypted on the physical host but remains accessible to the container through a secure bridge.

  • Step 1: LVM & Infrastructure Activation: Proxmox manages storage as Logical Volumes. Before any operation, we ensure the volumes are active and visible to the system kernel using vgchange -ay pve.
  • Step 2: LUKS Encryption Layer: We initialized a LUKS partition on the logical volume. This adds an industry-standard encryption layer. Once initialized, the volume is « opened, » creating a virtual device in /dev/mapper/immich_crypt. All data written to this device is encrypted before it hits the physical disk.Bashcryptsetup luksFormat /dev/pve/vm-141-disk-2 cryptsetup open /dev/pve/vm-141-disk-2 immich_crypt
  • Step 3: Filesystem & Permissions (The « Privilege Gap »): We formatted the decrypted volume with Ext4. However, since we are using unprivileged LXC containers for security, the container’s « root » user does not have the same ID as the host’s root. On the host, the container’s root is mapped to UID 100000. To allow Immich to save photos, we must recursively change the ownership of the host mount point to this specific ID.Bashmkfs.ext4 /dev/mapper/immich_crypt mount /dev/mapper/immich_crypt /mnt chown -R 100000:100000 /mnt/media
  • Step 4: Bind Mounting: Finally, we create a permanent bridge using Proxmox’s pct set command. This « plugs » the host’s decrypted folder directly into the container’s /mnt/immich_data directory.Bashpct set 141 -mp0 /dev/mapper/immich_crypt,mp=/mnt/immich_data

4. Troubleshooting: Encountered Obstacles

During implementation, we faced two major hurdles requiring deep system analysis:

  • Problem 1: Root Partition Saturation: Docker images are voluminous, and the container’s root partition quickly reached 95% capacity. We used df -h to diagnose the leak and confirmed that moving the heavy media library to the encrypted external volume was the only viable long-term solution.
  • Problem 2: Routing Conflicts (Connection Refused): Even with the firewall open, we could not access the web interface. We discovered that Docker’s internal iptables rules inside the container were conflicting with the NAT routing of the Proxmox host. We solved this by flushing the internal container rules:Bashiptables -F iptables -t nat -F iptables -P INPUT ACCEPT

5. Conclusion

This architecture demonstrates a professional approach to data privacy. By decoupling network routing (nftables), application management (Docker), and at-rest encryption (LUKS), we built a system that protects sensitive media while remaining highly scalable.

Tags:

No responses yet

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Latest Comments

Aucun commentaire à afficher.