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/