rationale Link to heading

  • simple https file server
  • handle let’s encrypt natively
  • public/private directories
  • portable with compose file (works with docker)
  • rootless as we need privileges separation
  • rhel distro with selinux for “more” security
  • log connections or not
  • can do local https if needed
  • can use a sophisticated auth system or go with with authelia

todo Link to heading

  • rate limit transfer per ip to manage overflow
  • implement corozawaf to inhibit some malicious attempts

setting up a firewall Link to heading

for firewalld on rhel system be sure to use the right zone

sudo systemctl enable firewalld
sudo firewall-cmd --list-all
sudo firewall-cmd --zone=public --permanent --add-service=https
sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --complete-reload

ufw should be as simple

installing podman Link to heading

sudo dnf install -y podman podman-compose

as we’ll use :80 :443 ports we must allow non-root user

sudo echo 'net.ipv4.ip_unprivileged_port_start=443' | sudo tee -a /etc/sysctl.d/allow_rootless_443.conf
sudo echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee -a /etc/sysctl.d/allow_rootless_80.conf
sudo sysctl -p /etc/sysctl.d/*

setup a user with no sudo privileges Link to heading

useradd -m podmanuser
passwd podmanuser

enable linger for this user

sudo loginctl enable-linger podmanuser

preparing the confs Link to heading

login as poduser

su --login podmanuser

create a directory to store all your mess stuff

mkdir -p files.domain.tld/{secret,site}
cd files.domain.tld

here is the compose file

files.domain.tld/podman-compose.yml

version: "3.9"
name: files.domain.tld
services:
  caddy:
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:Z
      - ./site:/var/www/html:Z
      - caddy_data:/data
      - caddy_config:/config
volumes:
  caddy_data:
  caddy_config:
  • :Z is for selinux context to change the security labels to the container + it adds category labels to protect from other container access
  • webserver’s root is ~/home/podmanuser/files.domain.tld/site/
  • caddy_data and caddy_config are image’s volumes not a local directory like ./

then caddy container will load Caddyfile which

  • use real A/AAAA domain name record pointing to your server’s ip for letsencrypt/tls
  • use zstd gzip compression
  • setup the root of your server ~/home/podmanuser/files.domain.tld/site
  • users need to authenticate to access ~/home/podmanuser/files.domain.tld/site/secret directory
  • enabling logs keeping 1y/12 files (optionnal)

hashed passsword uses bcrypt mkpasswd -m bcrypt

files.domain.tld/Caddyfile

files.domain.tld {
    root * /var/www/html
    encode zstd gzip
    file_server browse
    basic_auth /secret/* {
                anon4 $2b$05$y0AOWGbRKo39veqBy42SOeNMGAmp7uthedCRcY52C38yOvq6UWbZii
                anon6 $2b$05$9CTcvumEU/h1S5IYMQE79eQnkx4eHQjqXvuVDOatctbYFN82nRsS6
        }
    log {
        output file data/access.log {
            format json
            roll_local_time
            roll_keep     12
            roll_keep_for 365d
        }
    }
}

starting the container Link to heading

start container without sudo as podmanuser

  • if podman ask you for the repository use the docker repo
podman-compose up -d
podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS        PORTS                                       NAMES
9a107827141a  docker.io/library/caddy:latest  caddy run --confi...  6 minutes ago  Up 6 minutes  0.0.0.0:443->443/tcp, 0.0.0.0:443->443/udp  files.domain.tld_caddy_1

troubleshooting Link to heading

if you have issues launching podman

Error: open /etc/cni/net.d/netavark.lock: permission denied

comment this line out

/usr/share/containers/containers.conf

sed '/network_config/s/^/#/g' /usr/share/containers/containers.conf

restart podman service

sudo systemctl restart podman

if you have this error

ERRO[0000] XDG_RUNTIME_DIR directory "/run/user/1000" is not owned by the current user

then double check linger and eventually reboot

to check podman’s images status

podman ps -a

this error

Error: adding pod to state: name "pod_files.domain.tld" is in use: pod already exists
Error: creating container storage: the container name "files.domain.tld_caddy_1" is already in use by 7710a4ee509d2d5aecb465c6c8162c79d513f4723edb1ae8a9467fb8e0b61f6f. You have to remove that container to be able to reuse that name: that name is already in use, or use --replace to instruct Podman to do so.

means you need to properly stop the stack

podman-compose down

if you need a fresh restart and delete everything

podman stop --all && podman rm --all && podman rmi --all && podman volume prune -f && podman network prune -f

then check with

podman ps -a

troubleshoot your caddy container

podman logs files.domain.tld_caddy_1

troubleshoot caddy webserver

podman exec -it files.domain.tld_caddy_1 /bin/sh
less data/access.log
selinux troubleshooting Link to heading
  • this is not needed is you properly setup :Z or :z depending on the context

try to set it up by using sealert

do not forget to uninstall sudo dnf remove -y setroubleshoot-server after use because it eats ressources

sudo dnf install -y setroubleshoot-server
sudo semodule -DB
sudo sealert -l "*"

for example

type=AVC msg=audit(1725402348.892:5107): avc:  denied  { open } for  pid=145060 comm="caddy" path="/etc/caddy/Caddyfile" dev="sda5" ino=421 scontext=system_u:system_r:container_t:s0:c564,c754 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0
  • optionnal if :Z option doens’t work in the compose

then check the alerts and apply procedures

ausearch -c 'caddy' --raw | audit2allow -M my-caddy
semodule -i my-caddy.pp
semodule -X 300 -i my-caddy.pp
sudo chcon -t etc_t /home/podmanuser/files.domain.tld/Caddyfile -R
sudo chcon -t httpd_sys_content_t /home/podmanuser/files.domain.tld/site -R
sudo chcon -t httpd_sys_content_t /home/podmanuser/files.domain.tld/www -R
sudo chcon -t httpd_sys_rw_content_t /home/podmanuser/files.domain.tld/site -R

ressources : Link to heading

https://github.com/containers/podman/blob/main/rootless.md

https://caddyserver.com/docs/quick-starts/static-files

https://caddyserver.com/docs/caddyfile/directives/file_server

https://github.com/greenpau/caddy-security/blob/main/README.md

https://infotechys.com/setting-up-a-caddy-server-using-podman/

https://codewithhugo.com/docker-compose-local-https/

https://caddy.community/t/securing-web-apps-with-caddy-and-authelia-in-docker-compose-an-opinionated-practical-and-minimal-production-ready-login-portal-guide/20465