I managed to get Photostructure running on FreeBSD according to one of the potential methods I listed above: running within a Bhyve VM. I’m going to document below how I did it so that others can replicate the install and so that I can remember it myself. Also, it would be useful to hear from others if I overlooked some things and/or if there is an easier way to handle something.
How to Install Photostructure on FreeBSD
Approach
- Install Alpine Linux in a dedicated Bhyve VM
- Install Docker and docker-compose inside of Alpine Linux VM
- Mount directories from host inside of Alpine linux VM using SSHFS
- Configure docker-compose file & install
- Set-up automatic loading
1. Install Alpine Linux in a dedicated Bhyve VM
First, install the dependencies for Bhyve as well as vm-bhyve, which helps manage Bhyve Virtual Machines with an easy to understand CLI.
Note: most of what follows comes from this very helpful YouTube video
1a. Install vm-bhyve and set-up volumes
The following is mostly a replication of the vm-bhyve quick-start instructions
# pkg install vm-bhyve
Set up ZFS dataset for bhyve. Be sure to use zfs list
to check your root data pool off of which you will create your new dataset, mine is zroot
.
# zfs create zroot/vm
Enable Bhyve virtualization via sysrc
:
# sysrc vm_enable="YES"
# sysrc vm_dir="zfs:zroot/vm"
Tell vm-bhyve to initialize its directories:
$ vm init
Copy the Alpine Linux vm-bhyve template into your vm-bhyve working directory:
# cp /usr/local/share/examples/vm-bhyve/alpine.conf /zroot/vm/.templates/
Modify the template. You will need to replace all instances of “vanilla” with “lts” for Alpine but other than that the defaults will work. I gave mine 8 cpu cores and 16GB of RAM but do what works for you.
Set-up a “virtual switch” for networking:
# vm switch create public
“public” is just a name suggested by the quick-start, it can be anything
# vm switch add igb0
Replace igb0
here with your primary network device returned by ifconfig
Have vm-bhyve download the Alpine Linux installation image. Note, vm-bhyve stores these isos in a hidden directory that is a sibling of the above .templates
directory.
$ vm iso {alpine_linux_iso_url}
Create the virtual machine that we will be using:
I’m naming it “docker” but you can name it whatever you like. -t
refers to the template name (sans extension) and -s
tells it the size. Since we used ZFS above the size isn’t fixed but can expand to the amount listed. I gave mine 100GB capacity.
# vm create -t alpine -s 100G docker
# vm list
will show your new virtual machine (note Alpine hasn’t been installed yet)
Install Alpine Linux into the VM:
# vm install docker alpine_iso_file_name.iso
.
Note, run vm iso
to get the full file name and copy-paste it into the above command.
Attach to your vm console:
# vm console docker
Here, you will finish the Alpine installation from inside of the VM. Do whatever you would ordinarily do for Alpine Linux. Personally, I just used root
for everything since this is inside of a VM and docker wants to run as root anyway.
2. Install Docker and docker-compose inside of Alpine Linux VM
Allow Alpine Linux to use all apk repositories by uncommenting all lines in /etc/apk/repositories
. Then, run apk update
and proceed to install docker and docker-compose:
docker # apk update
docker # apk add docker docker-compose
Set up docker to run at boot and start it now:
docker # rc-update add docker boot
docker # service docker start
3. Mount directories from host inside of Alpine linux VM using SSHFS
I want to use directories on my host for holding photos so that I can easily back them up with my normal system backups. So, I’ll be mounting those host directories into the Alpine Linux VM while leaving the tmp directory directly in the VM for speed.
The first step is to generate an SSH key on the vm and add that to the known_hosts
on the host computer. I won’t go into how to do that here as it’s pretty straightforward.
If you configured the networking as above the host and the vm will each have their own unique IP addresses, which you can query using ifconfig
or something similar. I have my router set these as static for both the host and the vm so the IPs don’t change and can reliably connect without local DNS.
Once you have the keys set up then you’ll need to install sshfs
on your Alpine vm:
docker # apk add sshfs
Then, mount your desired directories:
Host → VM
/home/username/photostructure -> /mnt/photostructure
Before we go ahead and mount the above directory we need to create the mountpoint on the vm:
docker # mkdir -p /mnt/photostructure
Then, go ahead and mount it:
docker # sshfs username@ip.address:photostructure /mnt/photostructure
4. Configure docker-compose file & install
First, let’s create the volumes that will be used by Photostructure. Note, these will only be in the vm and not mounted from the host.
source (inside of vm but not inside of docker images):
docker # mkdir -p "${HOME}/.cache/photostructure"
docker # mkdir -p "${HOME}/.config/PhotoStructure-docker"
docker # mkdir -p "${HOME}/.config/PhotoStructure/logs
Now, create a directory for photostructure to store its Docker information:
docker # mkdir ~/photostructure && cd ~/photostructure
Let’s create a docker-compose.yml
file now:
docker # vi docker-compose.yml
The contents of this file should be according to the one in the official Photostructure instructions for docker-compose.
Some relevant portions:
# mounted library from host using sshfs
- type: bind
source: /mnt/photostructure
target: /ps/library
...
environment:
# necessary to keep the local library inside the vm for speed
- "PS_FORCE_LOCAL_DB_REPLICA=1"
Those are the only differences between what you need and what’s in the official documentation. Oh, and do not include the user: port
line as we want to use root
.
5. Set-up automatic loading
We set up Docker to run automatically when the VM starts above and the compose file will automatically start PhotoStructure. However, the sshfs directories will not be mounted at this time from the host. I’ve attempted to do this by modifying /etc/fstab
but can’t seem to get it to work with sshfs properly so that the directories are mounted before PhotoStructure starts.
Finally: Run
On your VM from within the directory that holds your docker-compose.yml
file:
docker # docker-compose up --detach
Now, on your host (or any device on your local network) open a browser and navigate to:
http://ip.of.vm:1787
If all worked you should see PhotoStructure up and running!