This is my (not so) little guide to switching from non-docker to docker version of Seafile in the easiest, and most secure way I could come up with.
It’s clear that Seafile is only going to be distributed as a docker image in the future, so since I have the time now, I figured I should learn how I would convert to using the docker version. The process outlined in the Seafile documentation will get a working docker installation, but it isn’t the most secure setup. I am recording the alternative steps I came up with for my setup in case they are useful to anyone else.
First, a bit about why I don’t want to use the docker edition. I already run Seafile in its own server so the container stuff does nothing for me; the separate VM is more thorough isolation than a container. Getting a backup of the entire VM is much easier than backing up a container (since I already have the infrastructure for VM backups). I tend to try to run things in as secure a way as I can, so installing programs as a black box image that’s hard to inspect doesn’t really appeal to me, and the fact that Docker requires another daemon running as root on the server (and setting the data directories’ permissions to a=rwx) is also concerning. This seems like importing a lot of complexity and attack surface unnecessarily.
And a bit about how my setup currently works, since this is the starting point for my process. My seafile VM runs from a pretty small OS disk image (cloned from a generic server image). The VM has 2 additional virtual disks, a small one for the database (/database) and a larger one for the seafile data (/seafile-data). The reverse proxy, authelia (for OAUTH) and other services all run in separate VMs, isolated by firewalls, vlans, and etc. Since I have the reverse proxy, and OAUTH, and colabora working with seafile version 11, I want to make as few changes outside of the seafile VM as possible for the upgrade.
OK, with the background out of the way, here’s my process to upgrade from non-docker version 11, to docker edition of version 12. This was all done on Debian 12, so if you are on another distribution some of the podman stuff might be different. Please share here if you find a difference.
- Install podman
I will use podman instead of docker because it seems to have a better design for security. There is no daemon running all the time, and everything with podman can be run as a user instead of root. I also found it easier to install, and a tiny bit faster. Also it will happily read the docker files, so there’s not much you have to do different.
apt install podman-docker systemd-container
- Create a user for the containers to run as. I decided to name mine podman. We will also need to turn on “linger” for this user so the container can run even when the user is not logged in. I put the podman user’s home directory on the /seafile-data disk because the OS disk is small, and this is where the files downloaded to make the docker containers will be stored. It’s likely that the default home directory will work for you.
sudo adduser --home /seafile-data/podman-home --shell /usr/sbin/nologin podman
sudo loginctl enable-linger podman
-
Make note of the podman user’s subuids (or create if it wasn’t made for you).
cat /etc/subuid
There should be a line like:
podman:165536:65536
Which gives podman 65536 subuids starting at 165536. Make note of that number for later. -
Configure podman to use the overlay storage driver. This improves performance immensely. Everything seemed to say this is the default, but it wasn’t used until I manually configured it. So in the podman’s home directory, create the file
~/.config/containers/storage.conf
with this content:
[storage]
driver = "overlay"
- Reconfigure mariadb and memcached to accept connections over the network (because connections from the container look like remote connection from the network). Edit
/etc/mysql/mariadb.conf.d/50-server.cnf
to change the bind-address line to have the server’s real IP (not the docker IP, but server’s main IP). Edit/etc/memcached.conf
to change “-l 127.0.0.1” to instead have the server’s IP. Restart both:
sudo systemctl restart mariadb.service
sudo systemctl restart memcached.service
-
Set up firewall rules to block anything from the network from talking to mariadb and memcached. Be sure to test these rules after everyhting is set up. The exact steps depend on what firewall you are using, so I don’t have specifics that are likely to work for you (for example, mine is actually firewall rules on the Proxmox machines that host the seafile VM).
-
Stop and disable the old seafile services:
systemctl stop seafile.service
systemctl stop seahub.service
systemctl disable seafile.service
systemctl disable seahub.service
- Give the seafile user in the database permission to log in from remote machines, and give it control over the seafile databases when logged in remotely.
mariadb
GRANT ALL PRIVILEGES ON *.* TO 'seafile'@'%' IDENTIFIED BY 'PASSWORD' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON ccnet_db.* to 'seafile'@'%';
GRANT ALL PRIVILEGES ON seafile_db.* to 'seafile'@'%';
GRANT ALL PRIVILEGES ON seahub_db.* to 'seafile'@'%';
- Make a directory for the docker files, and download them:
mkdir /seafile-data/docker
cd /seafile-data/docker
wget -O .env https://manual.seafile.com/12.0/docker/ce/env
wget https://manual.seafile.com/12.0/docker/ce/seafile-server.yml
# Optional, I wanted the notification server, so I did
wget https://manual.seafile.com/12.0/docker/notification-server.yml
I decided not to include seadoc. It appears to be written in javascript, and I don’t have time to check over 400 npm packages aren’t subject to the famous npm supplychain attacks. Also seadoc doesn’t seem to be opensource (or at least I can’t find the source and license anywhere), so it seems to be prorietary, so I can’t expect that anyone besides the original developer has checked either. So that’s a solid pass for me, at least for now.
-
Edit these docker files to remove the caddy stuff, as described in the instructions in the manual for not using caddy ( Use other reverse proxy - Seafile Admin Manual ).
I made some additional changes beyond what was described there. I also removed the entire db and memcached sections since I already have a working database and memcached and don’t need to install another one of either. I also changed the ports that get forwarded out of the seafile-server.yml to look like this:
ports:
- "8000:8000"
- "8082:8082"
This will let us talk directly to Seafile without going through the nginx inside the container. This seemed necessary to get OAUTH working, but I now suspect it wasn’t. However, it still made it easier because this means the nginx config I was using on my reverse proxy works without any changes on this new Seafile version.
It also makes troubleshooting easier, because this way it is easier to use wireshark to see exactly what is going on. I don’t like that the container is still running an nginx process I don’t need, but at least that process is now out of the way and not causing problems (beyond wasting resources). Maybe someday a variable can added to the docker config that could let us not start nginx?
I also added the “NON_ROOT=true” in the .env file as part of my efforts to improve the security of this setup. This will start the Seafile programs inside the container as the seafile user instead of as root.
- Move the seahub-data from the old version, to the docker location:
mv /seafile-data/seafile/seahub-data/* /seafile-data/persistent-data/seafile/seahub-data
- Move the Seafile data from the old version to where docker expects it.
I tried with both of these to just set up docker to use those files where they already are, but that didn’t work. There were several problems, but mostly they were either giving the docker container access to files it doesn’t need, or putting in an extra mount-point or two, which broke uploads by making it impossible to move the temp files into the storage directory. So in the end moving these was just easier.
mv /seafile-data/data /seafile-data/persistent-data/seafile/seafile-data
- Add the “current_version” file. This doesn’t appear in the documentation (not that I could find at least). I found it while reading through scripts in the container. This is how it will know that you are doing an upgrade and so it needs to run the upgrade/upgrade_11.0_12.0.sh file for you. For me this was done with:
echo 11.0.13 > /seafile-data/persistent-data/seafile/seafile-data/current_version
That needs to go in the directory above the directory named “storage”. Obviously be sure to put your current version in this file, not mine.
- Create the logs directory. If you let the container create the logs directory for itself, the permissions will not be set on it correctly, and seafile won’t start (at least if you are using the “NON_ROOT=true” option). This should be fixed in future versions, but is easy enough for us to just work around now.
mkdir /seafile-data/persistent-data/seafile/logs
Continued in the next post…