Seafile in Docker with self-signed certificate
Introduction
Seafile is an open-source file-hosting and file-syncing software. It can be used to sync files across different devices in your possession. In comparison to other solutions like NextCloud, Seafile is very efficient in syncing large number of files (especially small files). I have used it in my homelab for a very long time so today, I will demonstrate how to install Seafile Community Edition with self-signed certificate using Docker.
OS used: Debian 13
Software used: Seafile 13
Source
About certificates
Why am I providing instructions for a self-signed certificate instead of Let's Encrypt? It's because standard Seafile installation uses HTTP challenge for obtaining Let's Encrypt certificate, but it's more flexible for homelab to use DNS challenge. To use DNS challenge you can install certbot and copy obtained certificate in place of self-signed certificate. We copy certificate because Docker cant' read symlinks. More details on how to use certbot and automatically copy certificate are in the article Obtaining Let's Encrypt certificate using Cloudflare.
Seafile characteristics
Here are some Seafile characteristics to evaluate if it's software for you:
- Good at syncing large number of files.
- There is a client application for Windows, Linux (terminal and GUI), MacOS, Android, iOS.
- It also has Web UI, so you can access files with web browser.
- When the client is uploading file to Seafile server it is using 'delta upload', which means it transfer only part of file that changed.
- When the client is downloading file from Seafile server it is not using 'delta', which means the client download whole file at each change.
- Because of 'delta upload' files are stored in blocks and can't be accessed directly by other programs (for example by external image gallery). But as admin you can access files, read more in Seafile FUSE extension.
Prerequisites
Create new virtual machine for example using this tutorial: Fast initialization of Debian VM using Ansible.
Install Docker
The official documentation recommends Docker as the preferred deployment method for Seafile. To install Docker run following command (taken from the Official Docker Docs how to Install Docker Engine on Debian):
$ sudo apt-get update && \
sudo apt-get install ca-certificates curl && \
sudo install -m 0755 -d /etc/apt/keyrings && \
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && \
sudo chmod a+r /etc/apt/keyrings/docker.asc && \
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
sudo apt-get update && \
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
For easier Docker management add your user to docker group. Otherwise you'll need to use sudo before every command involving Docker.
$ sudo usermod -aG docker <username>
<username> - enter your username
Login again to user account to reload user's groups membership and include docker group.
Firewall configuration
Currently on Linux, Docker manages firewall rules using iptables and dynamically creates rules that are needed at the system start. Debian by default uses nftables instead of iptables, but have compatibility layer enabled, so iptablescommands are still valid and Docker works correctly.
Docker creates its own firewall rules (such as forwarding traffic between containers), so it's better to disable your custom firewall rules in the system, and instead enable firewall for the whole virtual machine in Proxmox. For Seafile you would only need to open port 443 on the firewall.
Seafile docker compose files
To deploy Seafile using Docker download configuration files from Seafile repositories. Details are covered in Seafile Manual - Installation of Seafile Server Community Edition with Docker.
For basic installation you will only need following files:
.envseafile-server.ymlcaddy.yml
Create seafile-docker directory and make it accessible by docker group for easier management by your user:
$ folderpath=/opt/seafile-docker && \
sudo mkdir -m 770 ${folderpath} && \
sudo chown root:docker ${folderpath}
-m - set folder permissions
Download Seafile configuration files and change theirs ownership to include docker group:
$ cd /opt/seafile-docker && \
sudo wget -O .env https://manual.seafile.com/13.0/repo/docker/ce/env && \
sudo wget https://manual.seafile.com/13.0/repo/docker/ce/seafile-server.yml && \
sudo wget https://manual.seafile.com/13.0/repo/docker/caddy.yml && \
sudo chmod 660 ./* ./.* && \
sudo chown root:docker ./* ./.*
./.* - this is needed to include hidden .env file
.env
In file .env:
- Delete
seadoc.ymlfrom lineCOMPOSE_FILE='seafile-server.yml,caddy.yml,seadoc.yml'. We won't be using SeaDoc in this simple installation. SeaDoc is online collaborative document editor (it's a Seafile extension). - Modify following environment variables:
SEAFILE_SERVER_HOSTNAME- set your hostname e.g.myhomelab.mydomain.comSEAFILE_SERVER_PROTOCOL- set tohttpsTIME_ZONE- set your time zone e.g.America/Los_AngelesINIT_SEAFILE_ADMIN_EMAIL- set Admin user emailENABLE_SEADOC- set tofalse
Seafile 13 doesn't support Docker secrets, so passwords need to be entered into .env file. I tried using Docker secrets in seafile-server.yml but it didn't work. Docker secret is mounted in a file /run/secrets/your-secret-name and Seafile 13 take the string /run/secrets/your-secret-name as a password instead of actual content of the file. Maybe future versions of Seafile will support this feature.
Generating passwords
Following script will generate passwords and put them in the .env file:
$ filename=/opt/seafile-docker/.env && \
password_length=50 && \
password_characters='A-Za-z0-9!#()*+,-.:;<=>?@[]^_{|}~' && \
db_password=$(tr -dc ${password_characters} < /dev/urandom | head -c ${password_length}) && \
sudo sed -i "s/INIT_SEAFILE_MYSQL_ROOT_PASSWORD=ROOT_PASSWORD/INIT_SEAFILE_MYSQL_ROOT_PASSWORD=${db_password}/" ${filename} && \
db_user_password=$(tr -dc ${password_characters} < /dev/urandom | head -c ${password_length}) && \
sudo sed -i "s/SEAFILE_MYSQL_DB_PASSWORD=PASSWORD/SEAFILE_MYSQL_DB_PASSWORD=${db_user_password}/" ${filename} && \
seafile_password=$(tr -dc ${password_characters} < /dev/urandom | head -c ${password_length}) && \
sudo sed -i "s/INIT_SEAFILE_ADMIN_PASSWORD=asecret/INIT_SEAFILE_ADMIN_PASSWORD=${seafile_password}/" ${filename} && \
jwt_key=$(tr -dc ${password_characters} < /dev/urandom | head -c ${password_length}) && \
sudo sed -i "s/JWT_PRIVATE_KEY=/JWT_PRIVATE_KEY=${jwt_key}/" ${filename}
password_length- you can change the length of a passwords that will be generated. This value should be greater or equal than 32 because its the minimal required length forJWT_PRIVATE_KEY.password_characters- characters used in a password. This set exclude characters like" ' ` / \ & $ %because it causes problems withsed,docker compose, andmariadb.sed -i "s/existing_string/new_string/" filename- substitute string in a file (edit in place)
After running the script check if all passwords are set correctly.
In your password manager, you only need to store Admin email INIT_SEAFILE_ADMIN_EMAIL and password INIT_SEAFILE_ADMIN_PASSWORD to login in as Admin for the first time. The rest of the passwords are used internally by the containers.
caddy.yml
In the file caddy.yml you don't need to change anything. Caddy is used as reverse proxy for Seafile.
seafile-server.yml
Modify the following lines to use your own certificate with Caddy:
$ sudo vim /opt/seafile-docker/seafile-server.yml
services:
(...)
seafile:
(...)
volumes:
(...)
- "/opt/seafile-caddy/certs/cert.pem:/usr/local/share/ca-certificates/cert.crt" # add this line
(...)
labels:
# caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty} # comment this line
caddy: ${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty} # add this line
caddy.tls: "/data/caddy/certs/cert.pem /data/caddy/certs/key.pem" # add this line
caddy.reverse_proxy: "{{upstreams 80}}" # leave this line as is
(...)
Note
According to the Seafile documentation:
If you're using a non-public url like
my-custom-setup.local, you have to make sure, that the docker container can resolve this DNS query. If you don't run your own DNS servers, you have to addextras_hoststo your.ymlfile.
The problem is easy to spot, because without proper DNS resolution inside seafile container, you won't be able to edit markdown files created in Seafile Web UI.
If you have this issue add extras_hosts in seafile-server.yml:
services:
(...)
seafile:
(...)
networks:
(...)
extra_hosts:
- "my-custom-setup.local=192.168.1.89" # add this line with host DNS name and its IP address
Generate SSL certificate
Create folder for custom certificate:
$ folderpath=/opt/seafile-caddy && \
sudo mkdir -m 770 ${folderpath} && \
sudo mkdir -m 770 ${folderpath}/certs && \
sudo chown -R root:docker ${folderpath}
-m - set folder permissions
Generate self-signed certificate and private key:
$ cd /opt/seafile-caddy/certs && \
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -keyout ./key.pem -out ./cert.pem
Create containers
To run configured services use command:
$ cd /opt/seafile-docker && \
docker compose up -d
Using Seafile
Log in to https://<value_set_in_SEAFILE_SERVER_HOSTNAME> using the Admin email and password you provided during the Docker container setup. Create new user for normal operations. Install Seafile client on your devices and select directories for syncing.
Update Seafile
Before updating Seafile it's best to read information on the official site. Some configuration values are changing from version to version and there you can find updated .env and docker compose files.
Update Docker using unattended-upgrades
Install unattended-upgrades package:
$ sudo apt install unattended-upgrades
You can enable Docker automatic upgrades by editing file /etc/apt/apt.conf.d/50unattended-upgrades:
$ sudo vim /etc/apt/apt.conf.d/50unattended-upgrades
(...)
Unattended-Upgrade::Origins-Pattern {
"origin=Debian,codename=${distro_codename}-updates";
"origin=Debian,codename=${distro_codename},label=Debian";
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
// --- Add these lines ---
// Docker repository
"origin=Docker,suite=${distro_codename},component=stable";
// -----------------------
(...)
};
(...)
Test if config is correct by running command:
$ sudo unattended-upgrades --dry-run --debug
If you see the following line in the command output, then there's likely a problem with your configuration (ensure you didn't make any typos):
Marking not allowed <apt_pkg.PackageFile object: filename:'/var/lib/apt/lists/download.docker.com_linux_debian_dists_bookworm_stable_binary-amd64_Packages' a=bookworm,c=stable,v=,o=Docker,l=Docker CE arch='amd64' site='download.docker.com' IndexType='Debian Package Index' Size=230910 ID:12>