A simple guide for self hosting using podman and quadlets.
This guide is intended to consolidate the knowledge from various blogs, docs and forums into a single unified guide that is easy to understand and useful. It contains enough information to get you started but Further Reading is advised.
You should consider looking at the Security Recommendations to find some known security related mistakes which people who are new to self hosting may make (including some mistakes that I made in the past) and how to fix them. There may be some other security issues which I may be unaware of so due diligence is advised.
NOTE: If you find any issues with this guide please open a pull request so that the issues can be rectified.
- Podman containers are rootless. (i.e, they do not require root privileges and hence are more secure)
- Podman has a daemon-less architecture (i.e, it can run containers under the user starting the container)
- It is well integrated with the system and hence easier to manage if you are familiar with linux.
- They are lightweight.
- Podman CLI API is the same as that of docker so the commands are similar.
- It is compatible with docker-compose so you can migrate your existing configuration from docker to podman easily.
You should create the CNAME and ALIAS records as shown in the following figure. (The exact steps to change the records may vary based on the registrar but the records should be the same.) Create a username.duckdns.org record in DuckDNS and point it to your IP address.
On your router, you can either forward packets recieved on ports 80 and 443 to your PC or add your PC as a DMZ host. And set a static IP address for your PC on the LAN side.
Caddy should be able to automatically handle the SSL part but if you cannot open port 80 (because it is blocked by your ISP) then you may need to do it manually using certbot.
It will ask you for some general information like email and domain name. Give those details and continue.
sudo certbot certonly --manual --preferred-challenges dns -d "*.domain.tld"
You will be asked to add a TXT record which you need to include in your DNS records.
If successful, it will generate and give you the SSL Certificates which you need to add to include in your caddyfile.
You can install caddy from your linux distribution's repository or use a podman container.
Run it as a rootful container
You need to place the caddy container file in
/usr/share/containers/systemd/
or
/etc/containers/systemd/
Reload the systemd daemon
sudo systemctl daemon-reload
sudo systemctl start caddy.service
A proxy server, kernel firewall rule, or redirection tool such as redir may be used to redirect traffic from a privileged port to an unprivileged one (where a podman pod is bound) in a server scenario - where a user has access to the root account (or setuid on the binary would be an acceptable risk), but wants to run the containers as an unprivileged user for enhanced security and for a limited number of pre-known ports.
This method is not recommended because changing unprivileged ports start from the default 1024 may cause security issues.
For temporary testing:
sysctl net.ipv4.ip_unprivileged_port_start=80
This change will be undone after a restart.
To make it permanent:
Append this snippet to /etc/sysctl.conf
net.ipv4.ip_unprivileged_port_start=80
and then execute:
sudo sysctl -p
The rest of the steps are the same as that of any other rootless container so go to Running Podman Containers
Take a look at the Caddyfile in this repo to check out how to serve a static page, set up a reverse proxy, logging etc.
On Debian/Ubuntu based systems:
sudo apt install podman podman-compose
On Fedora: It is pre-installed.
You can change the SERVICE_USER variable to anything you like.
export SERVICE_USER="podman_user"
sudo useradd -r -m -d "/var/lib/${SERVICE_USER}" -s /bin/false "${SERVICE_USER}"
NEW_SUBUID=$(($(tail -1 /etc/subuid |awk -F ":" '{print $2}')+65536))
NEW_SUBGID=$(($(tail -1 /etc/subgid |awk -F ":" '{print $2}')+65536))
sudo usermod \
--add-subuids ${NEW_SUBUID}-$((${NEW_SUBUID}+65535)) \
--add-subgids ${NEW_SUBGID}-$((${NEW_SUBGID}+65535)) \
"${SERVICE_USER}"
sudo loginctl enable-linger "${SERVICE_USER}"
sudo -H -u "${SERVICE_USER}" bash -c 'cd; bash'
echo "export XDG_RUNTIME_DIR=/run/user/$(id -u)" > ~/.bashrc
source ~/.bashrc
Place the quadlet container files in the user's systemd directory.
cp /path/to/container /var/lib/${SERVICE_USER}/.config/containers/systemd/
Reload the systemd daemon
systemctl --user daemon-reload
Add this snippet to your container files to enable auto-start on boot
[Install]
WantedBy=default.target
# vaultwarden.container
[Container]
ContainerName=vaultwarden
Image=registry.hub.docker.com/vaultwarden/server:latest
AutoUpdate=registry
PublishPort=127.0.0.1:8080:80
Volume=./data:/data
[Service]
Restart=always
[Install]
WantedBy=default.target
Key | Description |
---|---|
ContainerName | Name of the container |
Image | The image from which the container will be built |
AutoUpdate | similar to io.containers.autoupdate label |
PublishPort | To expose a port |
Volume | To access a podman volume or to grant access to certain direcories on host file system |
- Keep the system and containers updated.
- Use a firewall. I use firewalld through firewall-config's GUI as it allows me to add rich rules through a GUI which can be quite useful. If you prefer a simpler alternative then use gufw (Uncomplicated Firewall GUI).
- By default, the ports are published to 0.0.0.0:<PORT_NUMBER>, you may want to change it to 127.0.0.1:<PORT_NUMBER> (localhost) otherwise podman will expose those ports to other systems on the network.
- Scan your web server for any open ports using online tools or if you are an advanced user you can use nmap from the terminal on another system to check for open ports. If you are not sure about which online tool to use, I mentioned the one that I use to scan for open ports in the Resources Section.
- If you do not intend to access the server through localhost and only use it via the registered domain name through the reverse proxy then remove the PublishPort line from container files (except the reverse proxy's container) and allow communication between the containers by adding all your hosted services and the reverse proxy that you use to a pod.
- If you want to block connections from certain countries or allow access to your server from certain whitelisted countries, you can use country IP block allocations from IPDeny.com.
As with any service or application that is exposed to the internet there are some risks involved but they can be mitigated to a great extent if you configure your system and server properly.
Alternatively, you can setup a VPN like Wireguard, Tailscale and Headscale to access your server remotely but this makes it somewhat harder to use as the user needs to have a client application otherwise you can use Cloudflare Tunnels.
Well, strictly speaking you do not need to have a domain name but it can be very useful as you can have sub-domain routing and it saves you from the pain of having to type in the IP address of your server each time to access it and if you have DHCP on the WAN side then good luck trying to find your server's new IP address after your ISP changes it while you are away.
I recommend buying a cheap domain name (the price of domain names depends on their names and top level domain) and if you are hosting the server from your PC at home like I do and have DHCP on the WAN side then use duckdns (free of cost) to automatically update the IP whenever it gets changed.
From what I read online, if you want something cheap and are new to self hosting, go for Hostinger or if you want a good one go for Cloudflare. I use Hostinger because it is cheap and my server has very few users since my server is meant for private use only. So far, I don't have anything to complain about.
You can also look at other Domain registrars if you don't want Hostinger or Cloudflare for some reason.
This is a subjective question and it is up to you to choose which one you want to use.
I would recommend caddy as I think it has the right balance between ease of configuration and flexibility. It is easy to read and it prevents misconfiguration to a certain extent.
Go to Awesome Selfhosted and find what you need. The link is in the Resources Section.
You can use it directly with podman compose or use Podlet to convert the docker-compose.yml file into a Quadlet. You may need to make a few changes depending on the application but in most cases this should not be necessary.
Yes, but I would not recommend it. If you create your own SSL records, you will have to add your Certificate Authority(CA) Certificate on every system where you access your server otherwise expect your browser to show warnings whenever you visit.
Container File | Name | What it does |
---|---|---|
caddy.container | Caddy | Reverse Proxy |
audiobookshelf.container | Audiobookshelf | Audiobook and E-book Management |
kavita.container | Kavita | E-books and Comics |
vaultwarden.container | Vaultwarden | Password Management |
duckdns.container | DuckDNS | Updates your duckDNS IP |
You can use the quadlets in this repo directly but I suggest you use it after you make the appropriate changes such as changing the volume mounts and exposed port numbers.
-
IPDeny.com provides downloads of country IP block allocations.
-
Podlet generates podman quadlet files from a podman command, compose file, or existing object.
-
You can use this for free port scans.
-
It is a list of Software services and web applications which can be hosted on your own server(s).