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.sh
  • scripts/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 + your devfs.rules.
  • templates/chromey-offline – avoids networked steps; use host-fetched pkgs.
  • templates/chromey-start – includes overlay/home/user/start.html to seed the browser start page.
  • templates/unicode-fonts – installs fonts + overlay/usr/local/etc/fonts/local.conf for wide Unicode fallback.

8) Verification checklist

  • bastille list shows chromey Up
  • jailchromey launches Ungoogled Chromium without password prompts (if doas configured)
  • 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.