Ungoogled-Chromium on a Jail
Date: 2026-02-08
Host: GhostBSD
Component: Ungoogled-Chrome
Chromey Installer
Note 2025-11-02 23:04:26
This document packages everything needed to install, back up, restore, and run Ungoogled Chromium inside a Bastille jail named chromey
in the JailFox style and more. After going through the process you have a jailed ungoogle-chromium with full video and audio support, emojis and fonts etc.
Just in case the chicken came before the egg, the process starts with a robust Home backup/restore flow so your profile/configs survive rebuilds. Then it walks through the templates, scripts, mounts, X11 fixes, and the launchers.
0) Tree of scripts and templates
├── profile_restore
│ ├── chromey_backup_home.sh
│ ├── chromey_restore_home.sh
│ ├── Chromey.tar.gz
│ └── README_CHROMEY_BACKUP_RESTORE.md
├── scripts
│ ├── chromey_copy_profile.sh
│ ├── chromey_create.sh
│ └── chromey_download_ungoogled.sh
└── templates
├── chromey-lite
│ ├── Bastillefile
│ └── devfs.rules
├── chromey-offline
│ └── Bastillefile
├── chromey-start
│ ├── Bastillefile
│ └── overlay
│ └── home
│ └── user
│ └── start.html
└── unicode-fonts
├── Bastillefile
├── hooks
│ └── README
└── overlay
└── usr
└── local
└── etc
└── fonts
└── local.conf
17 directories, 15 files
1) Backup & Restore add these first
Two host-side scripts safeguard the jail user’s home (/home/user inside chromey). They skip Chromium lock/cache directories so you don’t restore stale state.
1.1 Add the scripts
Create:
scripts/chromey_backup_home.shscripts/chromey_restore_home.sh
Backup:
#!/bin/sh
set -eu
DOAS="${DOAS:-doas}"
JAIL="${JAIL:-chromey}"
JAIL_USER="${JAIL_USER:-user}"
BASTILLE_ROOT="${BASTILLE_ROOT:-/usr/local/bastille}"
BACKUP_DIR="${BACKUP_DIR:-/var/backups/chromey}"
LABEL="${LABEL:-home}"
EXCLUDES_FILE="$(mktemp -t chromey_excludes.XXXXXX)"
trap 'rm -f "$EXCLUDES_FILE"' EXIT
cat >"$EXCLUDES_FILE" <<'EOF'
./.cache
./.config/ungoogled-chromium/SingletonCookie
./.config/ungoogled-chromium/SingletonLock
./.config/ungoogled-chromium/SingletonSocket
./.config/ungoogled-chromium/GPUCache
./.config/ungoogled-chromium/ShaderCache
./.config/ungoogled-chromium/Crashpad
./.config/ungoogled-chromium/Code Cache
./.config/ungoogled-chromium/OnDeviceHeadSuggestModel
./.config/chromium/SingletonCookie
./.config/chromium/SingletonLock
./.config/chromium/SingletonSocket
./.cache/fontconfig
./.pki
./Downloads
./.Trash
EOF
JROOT="$BASTILLE_ROOT/jails/$JAIL/root"
JHOME="$JROOT/home/$JAIL_USER"
if [ ! -d "$JHOME" ]; then
echo "ERROR: $JHOME not found (is the jail name/user correct?)" >&2
exit 1
fi
mkdir -p "$BACKUP_DIR"
DATESTR="$(date +%Y%m%d-%H%M%S)"
ARCHIVE="${BACKUP_DIR}/${JAIL}-${LABEL}-${DATESTR}.tar.zst"
SUMFILE="${ARCHIVE}.sha256"
echo "Backing up $JAIL:/home/$JAIL_USER to:"
echo " $ARCHIVE"
if command -v zstd >/dev/null 2>&1; then
COMPRESS="-I zstd"
else
echo "Note: 'zstd' not found; falling back to gzip." >&2
COMPRESS="-z"
fi
(
cd "$JHOME"
$DOAS tar $COMPRESS -cf "$ARCHIVE" --exclude-from "$EXCLUDES_FILE" --options globbing -s ':^\./::' .
)
sha256 "$ARCHIVE" > "$SUMFILE"
echo "Wrote:"
echo " $ARCHIVE"
echo " $SUMFILE"
echo "Done."
Restore:
#!/bin/sh
set -eu
DOAS="${DOAS:-doas}"
JAIL="${JAIL:-chromey}"
JAIL_USER="${JAIL_USER:-user}"
BASTILLE_ROOT="${BASTILLE_ROOT:-/usr/local/bastille}"
ARCHIVE="${ARCHIVE:-}"
SUMFILE="${SUMFILE:-}"
usage() { cat <<EOF
Usage:
JAIL=chromey JAIL_USER=user ARCHIVE=/path/to/home-YYYYmmdd-HHMMSS.tar.zst \\
${0##*/} [SUMFILE=/path/to/archive.sha256]
EOF
}
[ -n "$ARCHIVE" ] || { usage; exit 1; }
[ -f "$ARCHIVE" ] || { echo "ERROR: archive $ARCHIVE not found"; exit 1; }
if [ -n "${SUMFILE:-}" ] && [ -f "$SUMFILE" ]; then
echo "Verifying checksum: $SUMFILE"
if grep -q 'SHA256 (' "$SUMFILE"; then
sha256 -c "$SUMFILE"
else
sha256 -C "$SUMFILE"
fi
echo "Checksum OK."
else
echo "Note: No checksum provided; skipping verification." >&2
fi
JROOT="$BASTILLE_ROOT/jails/$JAIL/root"
JHOME="$JROOT/home/$JAIL_USER"
if [ ! -d "$JHOME" ]; then
echo "Creating $JHOME"
$DOAS mkdir -p "$JHOME"
if bastille status "$JAIL" 2>/dev/null | grep -qi running; then
UID=$($DOAS bastille cmd "$JAIL" id -u "$JAIL_USER" 2>/dev/null || echo 1001)
GID=$($DOAS bastille cmd "$JAIL" id -g "$JAIL_USER" 2>/dev/null || echo 1001)
else
UID=1001
GID=1001
fi
$DOAS chown -R "$UID:$GID" "$JROOT/home"
fi
TAR_I=""
case "$ARCHIVE" in
*.zst) TAR_I="-I zstd" ;;
*.gz|*.tgz) TAR_I="-z" ;;
*) TAR_I="" ;;
esac
echo "Restoring $ARCHIVE into $JHOME ..."
$DOAS tar $TAR_I -xpf "$ARCHIVE" -C "$JHOME"
if bastille status "$JAIL" 2>/dev/null | grep -qi running; then
UID=$($DOAS bastille cmd "$JAIL" id -u "$JAIL_USER" 2>/dev/null || echo 1001)
GID=$($DOAS bastille cmd "$JAIL" id -g "$JAIL_USER" 2>/dev/null || echo 1001)
else
UID=1001
GID=1001
fi
$DOAS chown -R "$UID:$GID" "$JHOME"
echo "Restore complete: $JHOME"
Make them executable:
chmod +x scripts/chromey_backup_home.sh scripts/chromey_restore_home.sh
1.2 Optional: keep only the last N backups
# Keep last 5 backups (host-side), delete older
ls -1t /var/backups/chromey/chromey-home-*.tar.* | awk 'NR>5' | xargs -r doas rm -f
1.3 Example usage
# Backup current jail home
DOAS=doas JAIL=chromey JAIL_USER=user BACKUP_DIR=/var/backups/chromey ./scripts/chromey_backup_home.sh
# Restore into a fresh jail
JAIL=chromey JAIL_USER=user ARCHIVE=/var/backups/chromey/chromey-home-YYYYmmdd-HHMMSS.tar.zst SUMFILE=/var/backups/chromey/chromey-home-YYYYmmdd-HHMMSS.tar.zst.sha256 ./scripts/chromey_restore_home.sh
2) Integrate backup/restore into chromey_create.sh
Add these guarded hooks so rebuilds preserve user state automatically.
# BEGIN: optional backup before rebuild
if [ "${BACKUP_BEFORE:-1}" = "1" ] && [ -x "./scripts/chromey_backup_home.sh" ]; then
echo "[chromey_create] Backing up jail home before rebuild..."
DOAS=${DOAS:-doas} JAIL=${JAIL:-chromey} JAIL_USER=${JAIL_USER:-user} BACKUP_DIR=${BACKUP_DIR:-/var/backups/chromey} ./scripts/chromey_backup_home.sh || true
fi
# END
…and after the jail is re-created and packages installed, restore the latest backup if present:
# BEGIN: optional restore after rebuild
if [ "${RESTORE_AFTER:-1}" = "1" ] && [ -x "./scripts/chromey_restore_home.sh" ]; then
latest=$(ls -1t /var/backups/chromey/chromey-home-*.tar.* 2>/dev/null | head -1 || true)
if [ -n "$latest" ]; then
echo "[chromey_create] Restoring latest home archive: $latest"
JAIL=${JAIL:-chromey} JAIL_USER=${JAIL_USER:-user} ARCHIVE="$latest" ./scripts/chromey_restore_home.sh || true
else
echo "[chromey_create] No backups found to restore."
fi
fi
# END
You can disable either step at runtime:
BACKUP_BEFORE=0 ./scripts/chromey_create.sh
RESTORE_AFTER=0 ./scripts/chromey_create.sh
3) Ungoogled Chromium package strategy
If pkg install ungoogled-chromium fails in-jail (repo mismatch), fetch on the host and mount inside the jail:
doas pkg fetch -y -o /tmp/chromeypkgs ungoogled-chromium xauth mesa-dri noto-basic
# fstab (host):
# /tmp/chromeypkgs /usr/local/bastille/jails/chromey/root/mnt/pkgs nullfs ro 0 0
# then inside the jail:
doas bastille cmd chromey sh -eu -c 'pkg add /mnt/pkgs/All/*.pkg'
This mirrors the JailFox approach and keeps reproducibility.
4) X11 access and sockets
Host must expose the X11 socket and allow local clients:
doas install -d -m 1777 /tmp/.X11-unix
doas chown root:wheel /tmp/.X11-unix
xhost +local:
Jail fstab should include (adjust paths to your setup):
/tmp/.X11-unix /usr/local/bastille/jails/chromey/root/tmp/.X11-unix nullfs ro 0 0
/home/matuzalem/Downloads /usr/local/bastille/jails/chromey/root/usr/home/user/Downloads nullfs rw 0 0
If you ever see resource deadlock avoided on mount, clear the path inside the jail and recreate it:
doas rm -rf /usr/local/bastille/jails/chromey/root/tmp/.X11-unix
doas mkdir -p /usr/local/bastille/jails/chromey/root/tmp/.X11-unix
5) Jail & devfs config
Ensure (sample jail.conf fields):
mount.devfs=1;
devfs_ruleset=1010;
securelevel=2;
Your devfs.rules (GPU/audio/DRM/DRI/mixer/dsp) should be applied on the host and referenced by the jail. Example ruleset name: devfsrules_chromey=1010.
6) Launchers (host-side)
/usr/local/bin/jailchromey
#!/bin/sh
if [ "$(id -u)" -eq 0 ]; then
echo "Running the Webbrowser as root is not encouraged."
echo "Aborting."
exit 1
fi
xhost +local:
if [ -x /usr/local/bin/doas ]; then
/usr/local/bin/doas /usr/local/libexec/jail-chromium-exec "$@"
elif [ -x /usr/local/bin/sudo ]; then
/usr/local/bin/sudo /usr/local/libexec/jail-chromium-exec "$@"
else
echo "Need either security/doas or security/sudo to proceed."
exit 1
fi
/usr/local/libexec/jail-chromium-exec
#!/bin/sh
JAIL=chromey
JUSER=user
BROWSER=/usr/local/bin/ungoogled-chromium
bastille start "$JAIL" >/dev/null 2>&1
bastille cmd "$JAIL" su - "$JUSER" -c "setenv DISPLAY $DISPLAY; exec $BROWSER $1"
Make executable:
doas chmod +x /usr/local/bin/jailchromey
doas chmod +x /usr/local/libexec/jail-chromium-exec
Optional: passwordless launch via doas
/usr/local/etc/doas.conf:
permit nopass keepenv :wheel
7) Templates quick notes
templates/chromey-lite– minimal packages + yourdevfs.rules.templates/chromey-offline– avoids networked steps; use host-fetched pkgs.templates/chromey-start– includesoverlay/home/user/start.htmlto seed the browser start page.templates/unicode-fonts– installs fonts +overlay/usr/local/etc/fonts/local.conffor wide Unicode fallback.
8) Verification checklist
bastille listshowschromeyUpjailchromeylaunches Ungoogled Chromium without password prompts (ifdoasconfigured)- Windows display normally on the host X11 desktop
- Backups appear under
/var/backups/chromey/and can be restored
9) One-command rebuild (optional)
# Full cycle with automatic backup-before + restore-after:
BACKUP_BEFORE=1 RESTORE_AFTER=1 ./scripts/chromey_create.sh
Disable either step for a clean rebuild:
BACKUP_BEFORE=0 ./scripts/chromey_create.sh
RESTORE_AFTER=0 ./scripts/chromey_create.sh
10) Now we have [maybe]
- Isolation: browser inside a jail with tight devfs rules.
- Reproducible: templates lock system bits; scripts standardize actions.
- Portable: home backup/restore preserves user state and avoids Chromium lock pitfalls.
- Smooth UX: host launchers +
xhost +local:make it feel native on the desktop.