Setting Up a Read-Only, Docker-Served JBrowse 2 Instance with Remote Genome Storage via sshfs
A step-by-step playbook for publishing any reference genome in JBrowse 2 on a Linux server using only Docker, nginx, sshfs, samtools/htslib and the JBrowse CLI. The guide shows how to 1. install the minimal software stack, 2. mount a read-only genome directory from a remote server with sshfs, 3. convert and index FASTA + GFF3 files (BGZF + tabix), 4. create a JBrowse site, add assemblies and tracks via symlinks (no data duplication), 5. serve the site through an nginx-alpine container, and 6. troubleshoot common 404/403 and permission pitfalls. Every command is copy-paste-ready and uses clear placeholders (`<SITE>`, `<MOUNT>`, `<REMOTE_HOST>`, etc.) so the same recipe works on any Linux machine—laptop, HPC node, VM or cloud instance.
managementVersion History
Version 1 Current
Effective: 2025-07-03First version.
Procedure Steps (Version 1)
1 Install prerequisites (once per server)
# Ubuntu / Debian
sudo apt-get update
sudo apt-get install docker.io fuse sshfs
sudo usermod -aG docker $USER # let yourself run Docker without sudo
newgrp docker # activate the new group in this shell
CentOS/RHEL – yum install docker, enable & start docker.service.
Make sure /etc/fuse.conf contains user_allow_other (uncomment if needed).
2 Create the folders that will hold the site and mount
sudo mkdir -p <SITE> # e.g. /opt/jbrowse-site
sudo mkdir -p <MOUNT> # e.g. /mnt/genomes/h_armigera
sudo chown $USER:$USER <SITE> <MOUNT>
3 Mount the remote genome directory read‑only
sshfs \
-o IdentitiesOnly=yes,reconnect,ro,allow_other,default_permissions \
-o uid=101,gid=101 \ # nginx inside the container = UID 101
<REMOTE_USER>@<REMOTE_HOST>:<REMOTE_DIR> \
<MOUNT>
What the options do
| option | reason |
|---|---|
ro |
keep the reference data safe |
allow_other,default_permissions |
let other processes (nginx) read through FUSE while still honouring UNIX mode bits |
uid=101,gid=101 |
inside the nginx container every file appears owned/readable by user nginx |
If the mount ever drops, run the same command to reconnect.
4 Make sure your reference files are BGZF‑compressed and indexed
(do this on either the remote host or locally inside <MOUNT>)
cd <MOUNT>
# convert the genome FASTA to BGZF
gunzip -c MyGenome.fa.gz | bgzip -c > MyGenome.fa.bgz
# index the FASTA (creates .fai and .gzi)
samtools faidx MyGenome.fa.bgz
# sort + bgzip + index the GFF3 annotation
gunzip -c MyGenome.gff.gz | sort -k1,1 -k4,4n | \
bgzip -c > MyGenome.sorted.gff.bgz
tabix -p gff MyGenome.sorted.gff.bgz
You should now have five files:
MyGenome.fa.bgz (BGZF FASTA)
MyGenome.fa.bgz.fai
MyGenome.fa.bgz.gzi
MyGenome.sorted.gff.bgz (BGZF GFF)
MyGenome.sorted.gff.bgz.tbi
(If you already received BGZF files and their indexes, just place them in the directory—no conversion needed.)
5 Create an empty JBrowse site
docker run --rm -v <SITE>:/data \
quay.io/biocontainers/jbrowse2:3.5.1--h71b9176_0 \
jbrowse create /data --force
The --force overwrites the blank template if you run it twice.
6 Add the assembly
docker run --rm \
-v <SITE>:/data \
-v <MOUNT>:/src:ro \
quay.io/biocontainers/jbrowse2:3.5.1--h71b9176_0 \
jbrowse add-assembly /src/MyGenome.fa.bgz \
--type bgzipFasta \
--name MyGenome \
--displayName "My species (v1)" \
--load symlink \
--out /data
--load symlink writes a small link into <SITE> instead of copying the 100‑MB FASTA.
7 Add the gene‑model track
docker run --rm \
-v <SITE>:/data \
-v <MOUNT>:/src:ro \
quay.io/biocontainers/jbrowse2:3.5.1--h71b9176_0 \
jbrowse add-track /src/MyGenome.sorted.gff.bgz \
--assemblyName MyGenome \
--trackId gene_models \
--name "Official genes" \
--load symlink \
--out /data
8 (Recommended) build the search index once
docker run --rm -v <SITE>:/data \
quay.io/biocontainers/jbrowse2:3.5.1--h71b9176_0 \
jbrowse text-index /data
This makes the search box jump to gene IDs quickly.
9 Launch nginx to serve the site
docker run -d --name jbrowse2 \
-v <SITE>:/usr/share/nginx/html:ro \
-v <MOUNT>:/src:ro \
-p <PORT>:80 \
nginx:alpine
Why the second -v?
Your FASTA and GFF symlinks point into /src, so that path must exist
inside the container.
10 View the browser
Open a browser to http://<SERVER_A_IP>:<PORT>/
- In the assembly dropdown choose MyGenome → Open.
- Tick the “Official genes” track.
You’re browsing the remote genome with zero local duplication.
11 Add more tracks later (browser stays running)
# example: RNA‑seq coverage BigWig
docker run --rm \
-v <SITE>:/data \
-v <MOUNT>:/src:ro \
quay.io/biocontainers/jbrowse2:3.5.1--h71b9176_0 \
jbrowse add-track /src/MyRNAseq.bw \
--assemblyName MyGenome \
--trackId rna_cov \
--name "RNA‑seq coverage" \
--load symlink \
--out /data
Just refresh the web page – no container restart is needed.