Skip to content

Releases: DtxdF/AppJail

v3.7.0

28 Mar 21:54

Choose a tag to compare

Changes between 3.6.0 and 3.7.0

  • Add ext_if & on_if to default columns in appjail-expose(1) (multiple networks can be used at the same time and it is common practice, so it is worthwhile to show which interface is currently in use for which ports).
  • Document ext_if, on_if, hport & jport keywords in appjail-expose(1).
  • Add health_type & recover_type to default columns in appjail-healthcheck(1) (It might be worthwhile to show these columns by default since healthcheckers are known to get mixed up in execution from the host or inside the jail).
  • Add appjail-oci(1) to "SUBCOMMANDS".
  • Use in6_addr structure for IPv6 addresses (#24).
  • Set the jail name explicitly when it consists only of numbers (If the jail name consists only of numbers, it is necessary to explicitly define a name since only jid will be defined and name will be undefined given in an error).
  • Add support for hooks.
  • Set network options in rc.conf(5) (this fixes the problem for some services that require a configured network stack, but fail to start because the IPv4 address is assigned after the jail is started).
  • Use appjail.dns.alt-name label as an alternative hostname.
  • Add dummy-hook.sh hook for appjail-dns.
  • Only execute the hook when it has the execution bit set in appjail-dns.

Full Changelog: v3.6.0...v3.7.0

v3.6.0

03 Jan 00:36

Choose a tag to compare

Hightlights

OCI

The Open Container Initiative (OCI) is an effort to create an open industry standard around container formats and runtimes. Now AppJail can interpret an OCI image to deploy the container using FreeBSD jails.

# mkdir -p srv database config
# touch database/database.db
# appjail oci run \
    -d \
    -o overwrite=force \
    -o virtualnet=":<random> default" \
    -o nat \
    -o template=/usr/local/share/examples/appjail/templates/freebsd-oci.conf \
    -o fstab="$PWD/srv /srv" \
    -o fstab="$PWD/database/database.db database.db <pseudofs>" \
    -o fstab="$PWD/config/settings.json /.filebrowser.json <pseudofs>:reverse" \
    -e FB_NOAUTH=1 \
    docker.io/dtxdf007/filebrowser filebrowser
...
[00:00:04] [ debug ] [filebrowser] Creating a container (name:appjail-d11dccc9113) from docker.io/dtxdf007/filebrowser ...
appjail-d11dccc9113
...
[00:00:53] [ debug ] [filebrowser] Inspecting config.conf:
[00:00:53] [ debug ] [filebrowser]     appjail_version: 3.5.0+cf99039fea3f622e6b908803485be77527755323
[00:00:53] [ debug ] [filebrowser]     birth: 1733694151
[00:00:53] [ debug ] [filebrowser]     jail_type: thick
[00:00:53] [ debug ] [filebrowser]     release_name: default
[00:00:53] [ debug ] [filebrowser]     osarch: amd64
[00:00:53] [ debug ] [filebrowser]     osversion: 14.2-RELEASE
[00:00:53] [ debug ] [filebrowser]     container: 1
[00:00:53] [ debug ] [filebrowser]     container_image: docker.io/dtxdf007/filebrowser
...
[00:01:07] [ info  ] [filebrowser] Detached: pid:69856, log:jails/filebrowser/container/2024-12-08.log

InitScript library

An InitScript is as powerful as any other sh(1) script, the problem is that although the built-in environment variables can help, they are not enough for some common tasks, that's why there is a "library" with some subroutines you can use, inspired by appjail-makejail(5).

initscript:

. "${LIBDIR}/initscript"

create()
{
    local volume_created
    volume_created=`LABEL:GET initscripts.volumes.shared`

    if [ -z "${volume_created}" ]; then
        VOLUME -m /shared shared-dir

        LABEL:ADD initscripts.volumes.shared 1
    fi
}

start()
{
    ARG enable_bpf 0
    ARG install_htop 0
    ARG install_nginx 0
    ARG nginx_conf
    ARG nginx_worker_processes auto
    ARG nginx_worker_connections 1024
    ARG nginx_keepalive_timeout 65
    ARG nginx_server_name localhost

    PARSE "$@"

    [ -d /shared ] || mkdir -p /shared

    local shared_mounted
    shared_mounted=`LABEL:GET initscripts.mounted.shared`

    if [ -z "${shared_mounted}" ]; then
        MOUNT /shared shared-dir "<volumefs>" ro || exit $?

        LABEL:ADD initscripts.mounted.shared 1 || exit $?
    fi

    if [ "${ARG_enable_bpf}" != 0 ]; then
        local bpf
        bpf=`LABEL:GET initscripts.devices.bpf`

        if [ -z "${bpf}" ]; then
            DEVICE:SET 'include $devfsrules_hide_all' || exit $?
            DEVICE:SET 'include $devfsrules_unhide_basic' || exit $?
            DEVICE:SET 'include $devfsrules_unhide_login' || exit $?
            DEVICE:SET 'path "bpf*" unhide' || exit $?
            DEVICE:SET 'path bpf unhide' || exit $?
            DEVICE:APPLYSET || exit $?

            LABEL:ADD initscripts.devices.bpf 1 || exit $?
        fi
    fi

    local htop_installed
    htop_installed=`LABEL:GET initscripts.packages.htop`

    if [ "${ARG_install_htop}" != 0 ] && [ -z "${htop_installed}" ]; then
        PKG install -y htop || exit $?

        LABEL:ADD initscripts.packages.htop 1 || exit $?
    fi

    local nginx_installed
    nginx_installed=`LABEL:GET initscripts.packages.nginx`

    if [ "${ARG_install_nginx}" != 0 ] && [ -z "${nginx_installed}" ]; then
        PKG install -y nginx || exit $?

        if [ -n "${ARG_nginx_conf}" ]; then
            if [ ! -f "${ARG_nginx_conf}" ]; then
                printf "%s: nginx configuration file cannot be found.\n" "${ARG_nginx_conf}"
                return 1
            fi

            local nginx_conf
            nginx_conf="/usr/local/etc/nginx/nginx.conf"

            cp -af "${ARG_nginx_conf}" "${APPJAIL_JAILDIR}/${nginx_conf}" || exit $?

            REPLACE "${nginx_conf}" WORKER_PROCESSES "${ARG_nginx_worker_processes}" || exit $?
            REPLACE "${nginx_conf}" WORKER_CONNECTIONS "${ARG_nginx_worker_connections}" || exit $?
            REPLACE "${nginx_conf}" KEEPALIVE_TIMEOUT "${ARG_nginx_keepalive_timeout}" || exit $?
            REPLACE "${nginx_conf}" SERVER_NAME "${ARG_nginx_server_name}" || exit $?
        fi

        SYSRC nginx_enable=YES || exit $?
        SERVICE nginx start || exit $?

        LABEL:ADD initscripts.packages.nginx 1 || exit $?
    fi
}

cmd()
{
    if ! CMD which -s htop; then
        echo "sysutils/htop is not installed!" >&2
        return 1
    fi

    CMD htop
}

custom:test_pwd()
{
    WORKDIR /shared

    CMD pwd
}

custom:test_env()
{
    INITENV

    CMD env
}

custom:test_chroot()
{
    CMD /bin/sh
}

custom:test_jaildir()
{
    JAILDIR /bin/sh
}

custom:test_local()
{
    LOCAL /bin/sh
}

stop()
{
    echo "Good byte!"
}

Console:

# appjail quick jtest \
    start \
    overwrite=force \
    alias \
    ip4_inherit \
    start_args="install_nginx=1" \
    start_args="install_htop=1" \
    initscript="$PWD/initscript"
...
[00:00:30] [ debug ] [jtest] Compiling fstab #0: /shared shared-dir <volumefs> ro 0 0
Updating FreeBSD repository catalogue...
Fetching meta.conf: 100%    178 B   0.2kB/s    00:01
Fetching data.pkg: 100%    7 MiB 324.1kB/s    00:23
Processing entries: 100%
FreeBSD repository update completed. 35543 packages processed.
All repositories are up to date.
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        htop: 3.3.0_5

Number of packages to be installed: 1

107 KiB to be downloaded.
[1/1] Fetching htop-3.3.0_5.pkg: 100%  107 KiB 109.9kB/s    00:01
Checking integrity... done (0 conflicting)
[1/1] Installing htop-3.3.0_5...
[1/1] Extracting htop-3.3.0_5: 100%
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 2 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        nginx: 1.26.2_5,3
        pcre2: 10.43

Number of packages to be installed: 2

The process will require 9 MiB more space.
2 MiB to be downloaded.
[1/2] Fetching nginx-1.26.2_5,3.pkg: 100%  558 KiB 571.2kB/s    00:01
[2/2] Fetching pcre2-10.43.pkg: 100%    1 MiB 483.7kB/s    00:03
Checking integrity... done (0 conflicting)
[1/2] Installing pcre2-10.43...
[1/2] Extracting pcre2-10.43: 100%
[2/2] Installing nginx-1.26.2_5,3...
===> Creating groups
Using existing group 'www'
===> Creating users
Using existing user 'www'
[2/2] Extracting nginx-1.26.2_5,3: 100%
=====
Message from nginx-1.26.2_5,3:

--
Recent version of the NGINX introduces dynamic modules support.  In
FreeBSD ports tree this feature was enabled by default with the DSO
knob.  Several vendor's and third-party modules have been converted
to dynamic modules.  Unset the DSO knob builds an NGINX without
dynamic modules support.

To load a module at runtime, include the new `load_module'
directive in the main context, specifying the path to the shared
object file for the module, enclosed in quotation marks.  When you
reload the configuration or restart NGINX, the module is loaded in.
It is possible to specify a path relative to the source directory,
or a full path, please see
https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/ and
http://nginx.org/en/docs/ngx_core_module.html#load_module for
details.

Default path for the NGINX dynamic modules is

/usr/local/libexec/nginx.
nginx_enable:  -> YES
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.
[00:01:57] [ debug ] [jtest] start() exits with status code 0
[00:01:57] [ debug ] [jtest] `/usr/local/appjail/jails/jtest/init` exits with status code 0
[00:01:58] [ debug ] [jtest] Unlocking jtest ...
[00:01:59] [ debug ] [jtest] Done.
# appjail fstab jail jtest
NRO  ENABLED  NAME  DEVICE   MOUNTPOINT  TYPE        OPTIONS  DUMP  PASS
0    1        -     /shared  shared-dir  <volumefs>  ro       0     0
# appjail volume list jtest
NAME        MOUNTPOINT  TYPE        UID  GID  PERM
shared-dir  /shared     <pseudofs>  -    -    -
# appjail label list jtest
NAME                        VALUE
initscripts.mounted.shared  1
initscripts.packages.htop   1
initscripts.packages.nginx  1
# appjail run -s test_pwd jtest
[00:00:02] [ debug ] [jtest] Running initscript `/usr/local/appjail/jails/jtest/init` ...
/shared
[00:00:03] [ debug ] [jtest] custom:test_pwd() exits with status code 0
[00:00:03] [ debug ] [jtest] `/usr/local/appjail/jails/jtest/init` exits with status code 0
# appjail run -s test_env -V env1=1234 -V env2=4321 jtest
[00:00:02] [ debug ] [jtest] Running initscript `/usr/local/appjail/jails/jtest/init` ...
env2=4321
env1=1234
SHELL=/bin/sh
HOME=/root
USER=root
BLOCKSIZE=K
MAIL=/var/mail/root
MM_CHARSET=UTF-8
LANG=C.UTF-8
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin
TERM=screen.xterm-256color
[00:00:02] [ debug ] [jtest] custom:test_env() exits with status code 0
[00:00:02] [ debug ] [jtest] `/usr/local/appjail/jails/jtest/init` exits with status code 0
# appjail stop jtest
[00:00:03] [ debug ] [jtest] Running initscript `/usr/local/appjail/jails/jtest/init` ...
Good byte!
[00:00:03] [ debug ] [jtest] stop() exits with status code 0
[00:00:03] [ debug ] [jtest] `/usr/local/appjail/jails/jt...
Read more

v3.5.0

02 Nov 17:37

Choose a tag to compare

Changes between 3.4.0 and 3.5.0

  • Clarified: more about cloned_interfaces option, resolv.conf(5) and appjail.conf(5) (thanks @Dieken)
  • Added: missing check for when priority is not defined.

Full Changelog: v3.4.0...v3.5.0

v3.4.0

11 Jul 23:05

Choose a tag to compare

Changes between 3.3.0 and 3.4.0

  • Added: BIND dynamic DNS update hook (thanks @bschwand).
  • Added: -h parameter appjail-limits(1) stats.
  • Added: Isotype.
  • Humanize numbers in appjail-image(1) metadata info:
    • Added: strlen:lib_humanize_number() function.
    • Use strlen:lib_humanize_number() function to show the size of an image in a human-readable format.
  • Added: EX_OK in sysexits.
  • Implemented: lock-mechanism while git cloning and/or updating.
  • Improved: devfs:lib_devfs_get_assigned_rulesets() function:
    • Instead of expanding the jail directories using a glob expression that may be limited by the ARG_MAX limit, we use a small but fast C program called get_assigned_rulesets to get all the rulesets assigned by the jails.

Full Changelog: v3.3.0...v3.4.0

v3.3.0

07 May 16:00

Choose a tag to compare

Changes between 3.2.0 and 3.3.0

  • Added: stop_env option in quick:
    • Documented: stop_env option in appjail-quick(1).
  • Added: run_env option in quick:
    • Documented: run_env option in appjail-quick(1).
  • Added: start_env option in quick:
    • Documented: start_env option in appjail-quick(1).
  • Added: LABEL instruction in Makejails:
    • Documented: LABEL instruction in appjail-makejail(5).
  • Added: label option in quick:
    • Documented: label option in appjail-quick(1).
  • Added: label command.
  • Enclose arguments in angle brackets:
    • To improve readability and facilitate differentiation between parameters, command switches and arguments, the latter are enclosed in angle brackets.
  • Added: appjail_dns_extra parameter to concatenate hosts(5)-like files.
  • Added: table library:
    • This library provides functions to beautifully print a table. Commands that print their values in table format will use this library to have less complexity and abstracting some things.
  • Added: patreon.
  • Added: man pages:
    • appjail(1).
    • appjail-ajspec(5).
    • appjail-apply(1).
    • appjail-checkOld(1).
    • appjail-cmd(1).
    • appjail-cpuset(1).
    • appjail.conf(5).
    • appjail-config(1).
    • appjail-deleteOld(1).
    • appjail-devfs(1).
    • appjail-disable(1).
    • appjail-dns(8).
    • appjail-ephemeral(7).
    • appjail-enable(1).
    • appjail-enabled(1).
    • appjail-etcupdate(1).
    • appjail-expose(1).
    • appjail-fetch(1).
    • appjail-fstab(1).
    • appjail-healthcheck(1).
    • appjail-help(1).
    • appjail-image(1).
    • appjail-initscript(5).
    • appjail-jail(1).
    • appjail-limits(1).
    • appjail-label(1).
    • appjail-login(1).
    • appjail-logs(1).
    • appjail-makejail(1).
    • appjail-makejail(5).
    • appjail-nat(1).
    • appjail-network(1).
    • appjail-pkg(1).
    • appjail-quick(1).
    • appjail-restart(1).
    • appjail-rstop(1).
    • appjail-run(1).
    • appjail-service(1).
    • appjail-start(1).
    • appjail-startup(1).
    • appjail-status(1).
    • appjail-stop(1).
    • appjail-sysrc(1).
    • appjail-template(5).
    • appjail-tutorial(7).
    • appjail-update(1).
    • appjail-upgrade(1).
    • appjail-usage(1).
    • appjail-user(8).
    • appjail-volume(1).
    • appjail-version(1).
    • appjail-zfs(1).
  • Added: script to install the bleeding-edge version much easier.
  • Added: support for exposing a range of ports.
  • Fixed: error handling when obtaining the ruleset number in appjail start.
  • Fixed: bug that marks an already created jail as dirty.
  • Improved: message when RUNAS utility does not exist (#5).
  • Added: DEFAULT_VIRTUALNET_MTU option:
    • In some environments (tested in one of mine) the MTU is very low (in my case 576) and some applications can break by not setting a correct MTU (tested with certbot), so it is necessary to set the MTU correctly for a Virtual Network.
  • Improved: Slogan:
    • Center text.
    • Reduce text size.
  • Improved: ImagoType.

Full Changelog: v3.2.0...v3.3.0

v3.2.0

24 Jan 05:37

Choose a tag to compare

Changes between 3.1.0 and 3.2.0

  • Check status code of wait(2) in cmd_edit.c.
  • Added: zfs.dataset in parameters.c (thanks @netchild).
  • Fixed: parse of environment variables when its value is empty.
  • Fixed: undefined variable NETWORK_GENERIC_BRG in network (The variable NETWORK_GENERIC_BRG is required for the detach command, as this variable is not defined, the command fails.).

Full Changelog: v3.1.0...v3.2.0

v3.1.0

11 Jan 17:24

Choose a tag to compare

Changes between 3.0.0 and 3.1.0

  • Added: {nullfs|<pseudofs>}:reverse feature.
  • Improved: AppJail image:
    • Add Imagetype.
    • Improve Slogan.
  • Improved: creation of a bridge (A lock file is used to ensure that the bridge is not attempted to be created by two or more processes at the same time.).
  • Fixed: bottleneck in repeat (sleep(1) command is now started after a command failure instead of executing on the first try. This ensures that the command exits as quickly as possible instead of waiting for the sleep(1) time and the command time.).

Full Changelog: v3.0.0...v3.1.0

v3.0.0

20 Dec 21:18

Choose a tag to compare

Highlights

VolumeFS

VolumeFS is another pseudo-file system implemented in AppJail to take advantage of what PseudoFS or NullFS does. The idea with this feature is to abstract more things. For example, if a user wants to use an application that uses php-fpm or apache and the application needs to have such files or directories with a specific owner or group or even file mode the user needs to create them on the host or jail and issue some commands wasting some initial time configuring the application instead of just using it. Worse, the application directory may be in a different directory depending on whether you use apache or php-fpm. Take a look at the following Makejail that take advantage of volumes: https://github.com/AppJail-makejails/dasherr#volumes

VolumeFS solves the above, the user does not have to worry about which directory to use, which file mode and which owner and group. The user only has to worry about the volume name. See the following example using appjail-director:

appjail-director.yml

options:
  - virtualnet: ':<random> default'
  - nat:

services:
  adminerevo:
    makejail: gh+AppJail-makejails/adminerevo
    name: adminerevo
    options:
      - expose: '8080:80'
    arguments:
      - adminerevo_design: 'pepa-linha'
      - adminerevo_plugins: 'login-password-less'
      - adminerevo_tag: '14.0-php82-apache'
    volumes:
      - adminerevo-plugins-file: adminerevo-plugins-file

default_volume_type: '<volumefs>'

volumes:
  adminerevo-plugins-file:
    device: .volumes/plugins.php
    options: ro

.env:

DIRECTOR_PROJECT=adminerevo

.volumes/:

tree .volumes/
.volumes/
└── plugins.php

1 directory, 1 file

plugins.php:

<?php

// See https://www.adminer.org/en/plugins/

$plugins = array(
    new AdminerLoginPasswordLess(password_hash(".", PASSWORD_DEFAULT)),
);

The user just has to run appjail-director up and adminerevo will be deployed.

Documentation: https://appjail.readthedocs.io/en/latest/fs-mgmt/#volumefs

Dynamic Environment Variables

Passing environment variables from the command line allows us to create applications with less effort in many cases, also this honors what many projects expect: configuring them through environment variables. Currently, there are some Makejails in the Centralized Repository that take advantage of this feature:

In the near future, for new Makejails, environment variables will be taken into account.

Changes between 2.10.0 and 3.0.0

  • Improved: RC scripts: appjail-natnet & appjail:
    • Changed: nohup(1) to daemon(8).
    • Use only daemon(8) when starting. Running commands in background when the system is stopping, i.e. when shutdown(8) is executed may cause some problems such as leaving some processes as zombies.
  • BREAKING-CHANGE: Added: VOLUME support:
    • Added: VOLUME instruction.
    • Added: volume command.
    • Added: volume option in quick.
    • Added: lib_check_volumename function in check_func.
  • BREAKING-CHANGE: Escape harmful characters in ENV (ENV accepts a variety of special characters because since its creation appjail, i.e. appjail makejail lacks a way to pass environment variables dynamically. Currently, this responsibility is appjail makejail -V. This change breaks Makejails that depend on variables created by, for example, ARG).
  • Added: support for escaping line-continuation.
  • Added: -V parameter in {run|start|stop}.
  • Disable random colors when ENABLE_COLORS is set to 0.
  • Fixed: COLOR_DEFAULT (COLOR_DEFAULT does not reset the bold escape sequence).
  • Added: -V in {enable|disable|enabled} ... {start|stop|run}.
  • Fixed: ADD returns 0 when it should not (pipefail is set only to this instruction to get the correct return code because if the tarball fetch fails, this does not imply that tar(1) fails).

Breaking Changes

  • Volumes represent a breaking-change because ./conf/volumes/ is added to the include/exclude list when importing/exporting an image. If the image does not have such a directory (i.e. an image created with an older version of AppJail), tar(1) will fail. To fix this problem, the image must be rebuilt. All Makejails in the Centralized Repository were rebuilt.

  • The harmful escape characters in ENV represent a breaking change because an older Makejail can use, for example, the dollar sign to use a variable created by, for example, ARG. If ENV uses the dollar sign, it is used in the jail environment, not in the host environment. Some other characters are escaped to avoid command execution. The main motivation for this change is to take advantage of the -V parameter in most commands to pass environment variables dynamically. If we do not take advantage of this parameter, we need to define parameter by parameter. See this real example: AppJail-makejails/metube@9eb349f

    With the -V parameter a Makejail is much easier to write as you can see, since we don't need to define ARG for each environment variable that uses upstream.

Full Changelog: v2.10.0...v3.0.0

v2.10.0

03 Dec 08:39

Choose a tag to compare

Changes between 2.9.0 and 2.10.0

  • Added: support for dynamic versioning.
  • Display the process to be killed in kill_child.sh.
  • Kill unused processes after stopping AppJail in start|stop (If AppJail is killed when the corresponding signal is received, a jail(8) process can be left, so after AppJail exits the jail(8) process is killed.).
  • Make local the config variable in kill_child.sh.
  • Fixed: typo executed -> execute in atexit.
  • Restore signals after execute atexit commands.
  • Improved: signal handling (Signals are handled asynchronously, so a blocking command can be terminated without hanging up. Now more signals are handled (SIGHUP SIGINT SIGQUIT SIGQUIT SIGQUIT SIGQUIT SIGTERM SIGXCPU SIGXFSZ SIGXFSZ SIGXFSZ EXIT) and others are ignored (SIGALRM SIGVTALRM SIGPROF SIGUSR1 SIGUSR2). And also all processes created by the parent process are terminated recursively after executing atexit.).
  • Added: missing license header in ajdns.sh.
  • Added: cpignore file to gitignore.
  • Ignore SIGINT for initscripts and the buildscript (The child processes are terminated successfully, but in an interactive session (using AppJail on a console) a CTRL-C (so a SIGINT) can close child processes like the buildscript or an initscript (both are really a sh(1) script). To work around this, SIGINT is ignored, but all other signals are not, so kill_tree.sh of the parent process will terminate the remaining processes afterwards.).
  • Added: --tmp parameter to git method in Makejail.
  • Make local the gitdir variable in makejail.
  • Added: pkg option in quick.
  • Mark the jail as clean once its execution has been completed in quick.
  • Issue a warning when the jail will use a dirty release directory.
  • Changed: the debugging level of the message that appears before removing the jail.

Full Changelog: v2.9.0...v2.10.0

v2.9.0

02 Nov 16:43

Choose a tag to compare

Highlights

Read the Docs

The documentation has been moved to Read the Docs. The format is better, beautiful and easily readable and shows all the features that AppJail offers you.

Some sections have been written for newbies to using AppJail, I hope this helps a lot:

Documentation: https://appjail.readthedocs.io/

PseudoFS

The purpose of this handy feature is to allow you to easily separate the data that should persist when removing the jail. For example, imagine you import an image and it comes with /usr/local/www/apache24/data/wp-content indicating a WordPress installation. Such files and subdirectories will be removed with the jail data and other things it contains. For this data to persist, you must move them to the host and mount them using mount_nullfs(8). You will probably need to stop the jail before moving the files as some applications may not be able to run correctly.

This pseudo-filesystem does this. It moves the data from the jail to the host when you run appjail fstab jail ... compile and mounts that file or directory using mount_nullfs(8), so that when you remove the jail, your data is safe.

# mkdir -p /tmp/var_tmp
# ls /tmp/var_tmp
# appjail fstab jail jtest set -d /tmp/var_tmp -m /var/tmp -t '<pseudofs>'
# appjail fstab jail jtest
NRO  ENABLED  NAME  DEVICE        MOUNTPOINT  TYPE        OPTIONS  DUMP  PASS
0    1        -     /tmp/var_tmp  /var/tmp    <pseudofs>  rw       0     0
# appjail restart jtest
...
[00:00:10] [ debug ] [jtest] Moving /usr/local/appjail/jails/jtest/jail//var/tmp/vi.recover -> /tmp/var_tmp/vi.recover ...
...
# appjail fstab jail jtest mounted
/usr/local/appjail/releases/amd64/13.2-RELEASE/default/release -> /usr/local/appjail/jails/jtest/jail/.appjail
/tmp/var_tmp -> /usr/local/appjail/jails/jtest/jail/var/tmp
devfs -> /usr/local/appjail/jails/jtest/jail/dev
# ls /tmp/var_tmp
vi.recover/

PseudoFS: https://appjail.readthedocs.io/en/latest/fs-mgmt/#pseudofs

Dynamic DEVFS Ruleset Management

The traditional approach requires you to first edit /etc/devfs.rules, write some DEVFS rules, reload with service devfs restart and set devfs_ruleset in your jail configuration file. AppJail supports this approach, but now you can use a modern way: let AppJail control the loading of your rulesets. You can define them using appjail quick or the DEVICE statement in your Makejail.

# appjail quick jtest \
    overwrite=force \
    start \
    device='include $devfsrules_hide_all' \
    device='include $devfsrules_unhide_basic' \
    device='include $devfsrules_unhide_login'
...
# appjail devfs list jtest
NRO  ENABLED  NAME  RULE
0    1        -     include $devfsrules_hide_all
1    1        -     include $devfsrules_unhide_basic
2    1        -     include $devfsrules_unhide_login

DEVFS: https://appjail.readthedocs.io/en/latest/DEVFS/

Source Tree

AppJail can now build the entire FreeBSD source tree for better customization, performance and more.

# appjail fetch src
[00:00:02] [ info  ] Build log will be releases/default/build/2023-10-12_06h18m40s.log
[00:00:02] [ info  ] Starting installworld with 8 jobs ...
[00:03:57] [ info  ] installworld finished!
[00:03:57] [ info  ] Starting distrib-dirs ...
[00:04:02] [ info  ] distrib-dirs finished!
[00:04:02] [ info  ] Starting distribution ...
[00:04:36] [ info  ] distribution finished!
[00:04:36] [ info  ] Starting delete-old delete-old-libs ...
[00:05:28] [ info  ] delete-old delete-old-libs finished!

Source Tree: https://appjail.readthedocs.io/en/latest/source-tree/

Acknowledgments:

Apply Makejails

Maybe you have a jail already created to which you want to make some changes, but simply running a Makejail is not useful for your case since it will be recreated, so you create a script in the language of your choice, but you realize that you need to write more things than simply creating a Makejail. The solution to this problem is to apply a Makejail to an existing jail to take advantage of the Makejail instructions.

Makejail.apply:

STAGE apply

PKG telegram-desktop \
    xpdf \
    librewolf
    mesa-dri

To apply this Makejail just execute appjail apply.

appjail apply xrdp Makejail.apply

Applying Makejails: https://appjail.readthedocs.io/en/latest/makejails/apply/

Acknowledgments:

Fair Image Bandwidth

To achieve greater fairness between the bandwidth of the nodes hosting the images, a randomized approach is used.

Shorter domain names

# ping -c4 redis
PING redis (10.42.0.16): 56 data bytes
64 bytes from 10.42.0.16: icmp_seq=0 ttl=64 time=0.244 ms
64 bytes from 10.42.0.16: icmp_seq=1 ttl=64 time=0.154 ms
64 bytes from 10.42.0.16: icmp_seq=2 ttl=64 time=0.216 ms
64 bytes from 10.42.0.16: icmp_seq=3 ttl=64 time=0.189 ms

--- redis ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.154/0.201/0.244/0.033 ms

DNS#using-shorter-domain-names: https://appjail.readthedocs.io/en/latest/networking/DNS/#using-shorter-domain-names

Changes between 2.8.0 and 2.9.0

  • Added: version_extra keyword in appjail jail list.
  • Migrated: https://appjail.readthedocs.io
  • Added DEVFS support:
    • .gitignore:
      • Added: find-number-from-start.
      • Added: find-smallest-missing-number.
    • etc/rc.d/appjail:
      • Added: devfs in REQUIRE.
    • Added: fnfs algorithm.
    • Added: fsmn algorithm.
    • Added: devfs command.
    • Added: device option in appjail quick.
    • Added: DEVICE instruction in appjail makejail.
    • Added: devfs_ruleset keyword in appjail jail list.
    • Added DEVFS support in appjail start.
    • Added: lib_check_varname function in share/lib/check_func.
    • Added: devfs library.
    • Added: select library.
    • Added: load-devfs-rules script.
    • Added: DEVFS_ASSIGN_ALGO option in AppJail configuration file.
    • Added: DEVFS_FNFS option in AppJail configuration file.
  • Fixed: lib_repeat:
    • Fixed: exit status (it returns 0 instead of the correct exit status).
    • Fixed: check for when the output is empty or not.
  • Fixed: usage limits remove keyword.
  • Fixed: typo limits -> limits_usage.
  • Added: IMAGE_DOWNLOAD_METHOD option in AppJail configuration file (This option is implemented to solve a problem, namely fairness when downloading an image between multiple sources. The random option is set by default as it appears to be fair, but more methods may be implemented in the future if this assumption is not accurate.).
  • Replaced: shell process with exec in share/appjail/scripts/ajuser.sh and share/appjail/scripts/runas.sh.
  • Fixed: functions and modules that may hang (These functions naively pass an argument to grep(1) relying on the -F flag to compare each entry. The problem is that if the user passes an invalid entry as -a, problems such as hangings or the like may occur. To fix this, simply add -- before the pattern to told to getopt(3) to stop processing further options.):
    • appjail fetch.
    • appjail login.
    • lib_check_signal.
    • lib_check_rctl*.
    • lib_check_path_traversal*.
  • Fixed: limits stats (it shows duplicate entries).
  • Added: support for applying Makejails.
  • Fixed: lib_check_func (lib_check_func may return 0 even if its argument is not a function but a program, which may lead to execute it instead of the intended function.).
  • Fixed: current directory when executing initscripts (When executing an initscript, the current directory should be the last current directory when processing the main Makejail, but it is the current directory where the initscript is located, which can break stages using some instructions like COPY or CMD --local. The build stage is not affected since it does not use initscripts.).
  • Removed: extra new line in share/appjail/scripts/run_jail.sh.
  • Added: Shorten Domain Names feature.
  • Added: JOBS option in AppJail configuration file.
  • Deprecated: appjail fstab jail ... -p flag.
  • Added: etcupdate command.
  • Added: appjail checkOld command.
  • Fixed: appjail update jail parameters.
  • Added: appjail deleteOld command
  • Added: appjail fetch src command.
  • Added: release option in appjail quick.
  • Removed: unused parameters in appjail update release.
  • Limited: depth of search in appjail fetch list.
  • Added: more checks for when errors occur after creating directories in a thinjail.
  • Ignored: files that do not exist when creating a thinjail.
  • Optimized: appjail jail list (Getting jail information in parallel is better and improves performance than doing it sequentially).
  • Fixed: syntax order in appjail fetch.
  • Implemented: PseudoFS.
  • Added: support for files when using nullfs filesystem.
  • Added: etc/rc.d/appjail-dns to uninstall target.

Full Changelog: v2.8.0...v2.9.0