Skip to content

Add AppJail as an alternative deployment tool#1

Merged
ahze merged 1 commit intodaemonless:mainfrom
DtxdF:main
Mar 14, 2026
Merged

Add AppJail as an alternative deployment tool#1
ahze merged 1 commit intodaemonless:mainfrom
DtxdF:main

Conversation

@DtxdF
Copy link
Copy Markdown
Contributor

@DtxdF DtxdF commented Mar 13, 2026

  • Add AppJail icon.
  • Add AppJail and Director to:
    • immich
    • mariadb
    • nginx-base
    • openspeedtest
    • postgres
    • redis

- Add AppJail icon.
- Add AppJail and Director to:
  - immich
  - mariadb
  - nginx-base
  - openspeedtest
  - postgres
  - redis
@ahze
Copy link
Copy Markdown
Member

ahze commented Mar 14, 2026

This is fantastic work! I’m really excited to see AppJail as a first-class deployment option!

I realized I haven’t properly documented our documentation pipeline, and I apologize for that oversight. Because of how it's currently set up, if I merge these manual edits to the .md files right now, the next automated run will unfortunately overwrite them.

For context, our deploy workflow automatically regenerates the site by pulling the compose.yaml and README.md files from each individual image repository. Those README.md files are themselves generated via the dbuild templates.

To get this merged, we have a couple of options:

The Short-Term Fix: I'm happy to temporarily disable the automated docs sync and merge this PR as-is so we can get your work live right away.

The Ideal Long-Term Fix: We port your AppJail logic into the central README.j2 template so that every image in the fleet gets these instructions automatically.

I'm happy to go with the short-term option for now to get this across the finish line. What are your thoughts?

@ahze
Copy link
Copy Markdown
Member

ahze commented Mar 14, 2026

I went ahead and disabled the docs generation and merging this.

@ahze ahze merged commit 5453364 into daemonless:main Mar 14, 2026
@DtxdF
Copy link
Copy Markdown
Contributor Author

DtxdF commented Mar 14, 2026

No problem! I'll create a pr for each image I've edited.

@DtxdF
Copy link
Copy Markdown
Contributor Author

DtxdF commented Mar 14, 2026

Oh, I’ve taken a closer look at the README.md.j2 file. I think it’s not a bad idea to add that logic so that the AppJail instructions are generated automatically, but for now, I’ll just submit a pr for each image I’ve edited. I think that’s simpler at this moment.

@DtxdF
Copy link
Copy Markdown
Contributor Author

DtxdF commented Mar 14, 2026

Oh, I’ve taken a closer look at the README.md.j2 file. I think it’s not a bad idea to add that logic so that the AppJail instructions are generated automatically, but for now, I’ll just submit a pr for each image I’ve edited. I think that’s simpler at this moment.

I don't think that's possible. After reading the README file for the images I've edited, it seems they differ slightly from daemonless-io and appear to have been automatically generated by dbuild. I think I'll wait until the documentation process is complete to avoid making mistakes.

Any other suggestions are welcome.

@ahze
Copy link
Copy Markdown
Member

ahze commented Mar 14, 2026

We actually had two separate templates, which was confusing and caused drift. I’ve just finished consolidating them—we now have a single "Source of Truth" template at dbuild/templates/README.j2. The daemonless-io site generator has been updated to pull directly from there.

To make AppJail a permanent part of the project, I’d love to help you get this into the template. Instead of submitting multiple PRs to individual images, we can add a few lines to each image's compose.yaml and let the template do the heavy lifting.

Here is an example of what I'm thinking for the metadata in compose.yaml:

x-daemonless:
  title: "MariaDB"
  # ... existing metadata ...
  appjail:
    makejail:
      options:
        - "container=boot args:--pull"
    director:
      options:
        - "virtualnet: ':<random> default'"
        - "nat:"

The template would then use this to auto-generate the tabs like this:

appjail-director.yml:

options:
{%- for opt in appjail.director.options %}
  - {{ opt }}
{%- endfor %}
services:
  {{ name }}:
    # ... auto-mapped from compose service definition ...

This way, AppJail support becomes a core feature for the entire fleet. If you're open to it, I can handle the template logic if you help me define the best default fields for the appjail section. What do you think?

@ahze
Copy link
Copy Markdown
Member

ahze commented Mar 14, 2026

should dbuild output appjail-director.yml .env , etc like it does for README.md?

what do you think?

@ahze
Copy link
Copy Markdown
Member

ahze commented Mar 14, 2026

I’ve been prototyping some updates to the init and template logic to automate more of the boilerplate. Here’s a look at where this is heading:

Init + generate example

[ahze@saturn ~/src/apache]$ dbuild init --freebsd-port www/apache24 --github --variants=pkg,pkg-latest  --port 80 --title Apache
[info] querying port metadata for www/apache24...
[info] querying runtime deps for apache24...
=== Port metadata ===
[ok] name:        apache24 (pkg: apache24)
[ok] description: The Apache HTTP Server Project is an effort to develop and maintain an open-sour...
[ok] license:     Apache-2.0
[ok] web:         https://httpd.apache.org/
[ok] category:    Network
[ok] run_deps:    perl5 pcre2 libxml2 libnghttp2 jansson gdbm expat curl apr
=== created /home/ahze/src/apache/.daemonless/config.yaml ===
=== created /home/ahze/src/apache/compose.yaml ===
=== created /home/ahze/src/apache/Containerfile.pkg.j2 ===
=== created /home/ahze/src/apache/root/etc/services.d/apache24/run ===
=== created /home/ahze/src/apache/root/healthz ===
=== created /home/ahze/src/apache/.github/workflows/build.yaml ===
=== scaffolded 6 file(s) (created) ===

This pulls metadata directly from the local ports tree — description from pkg-descr, license, WWW, runtime deps, and category mapping — and scaffolds a complete project. dbuild generate then produces the README.md and Containerfile from the templates.

[ahze@saturn ~/src/apache]$ dbuild generate
=== Generated README.md ===
=== Generated Containerfile.pkg ===

The AppJail section in the generated README shows exactly what users need to deploy via AppJail Director -- no manual work required:

[ahze@saturn ~/src/apache]$ grep -A30 appjail README.md
=== ":appjail-appjail: AppJail Director"
    **.env**:

    ```
    DIRECTOR_PROJECT=apache
    PUID=@PUID@
    PGID=@PGID@
    TZ=@TZ@
    ```

    **appjail-director.yml**:

    ```yaml
    options:
      - virtualnet: ':<random> default'
      - nat:
    services:
      apache:
        name: apache
        options:
          - from: @REGISTRY@/apache:latest
        oci:
          environment:
            - PUID: '@PUID@'
            - PGID: '@PGID@'
            - TZ: '@TZ@'
        volumes:
          - apache_config: /config
    volumes:
      apache_config:
        device: '@CONTAINER_CONFIG_ROOT@/@APACHE_CONFIG_PATH@'
    ```

    **Makejail**:

    ```
    OPTION container=boot args:--pull
    ```

And in compose.yaml, the bare appjail: key is what drives it — clean and minimal:

[ahze@saturn ~/src/apache]$ grep -A5 -B5 appjail compose.yaml
compose.yaml-  web_url: "https://httpd.apache.org/"
compose.yaml-  freshports_url: "https://www.freshports.org/www/apache24/"
compose.yaml-  user: "bsd"
compose.yaml-  mlock: false
compose.yaml-
compose.yaml:  appjail:
compose.yaml-
compose.yaml-  docs:
compose.yaml-    env:
compose.yaml-      PUID: "User ID for the application process"
compose.yaml-      PGID: "Group ID for the application process"

No boilerplate, no commented-out examples. If you want to override the defaults (custom virtualnet, multi-service depends_on, etc.), expand the key. Otherwise, leave it bare and the defaults just work.

Complex example: Immich

For multi-service stacks, the full appjail: schema handles everything. Here's the x-daemonless block from immich-server/compose.yaml:

appjail:
  director:
    options:
      - "alias:"
      - "ip4_inherit:"
  depends_on:
    - name: database
      image: ghcr.io/daemonless/immich-postgres:latest
      template: "immich-postgres-template.conf"
      env:
        POSTGRES_PASSWORD: "!ENV '${DB_PASSWORD}'"
        POSTGRES_USER: "!ENV '${DB_USERNAME}'"
        POSTGRES_DB: "!ENV '${DB_DATABASE_NAME}'"
      volumes:
        db-data: "/var/lib/postgresql/data"
    - name: redis
      image: ghcr.io/daemonless/redis:latest
      env:
        LANG: "C.UTF-8"
        TZ: "!ENV '${TZ}'"
      volumes:
        redis-data: "/config"
    - name: immich-machine-learning
      image: ghcr.io/daemonless/immich-ml:latest
      env:
        HF_HOME: "/cache/huggingface"
        MPLCONFIGDIR: "/tmp"
        TZ: "!ENV '${TZ}'"
      volumes:
        model-cache: "/cache"

That metadata drives the full generated appjail-director.yml -- no manual authoring needed. The simple case (bare appjail:) and the complex case (full depends_on stack) both flow through the same template.

I'm still learning the ropes with AppJail, so I'd love your thoughts on this schema. Does this approach look solid to you before I commit more time to this path?

@DtxdF
Copy link
Copy Markdown
Contributor Author

DtxdF commented Mar 14, 2026

Yeah, as I said, I have no problem adding logic to your template, but right now I don’t think I can do it because I’m not entirely sure how the process works. For example, let’s say I just want to edit nginx-base to fix a typo: what steps do I need to perform?

Maybe I’m a bit confused right now, and the process is actually simpler. But if you want to simplify this process, take a look at how I do it in Makejails:

Basically, if I or any other user wants to fix a typo, all we have to do is edit README.template, run update.sh, commit, push, and create a pr. Yeah, you’ll end up with two copies (the template and the resulting file), but the file size is negligible. For bulk updates, that's what update.conf is for, so you just need to edit a single line (probably using a script that loops through each repository) and follow the same process described above.

If you prefer the dbuild template, Director has a man page called director-spec(5) with the specification. I don't plan on adding any more parameters in the near future, so it's very stable right now. But I think the images I have added (even with immich, which is the most complex) are enough to see a pattern and add the logic to the template. Just keep in mind that the .env environment variables are for the Director process, not the jail/container. You still need to use !ENV to access those environment variables, so to simplify, you can just pass environment variables from compose.yaml to oci.environment parameter.

@ahze
Copy link
Copy Markdown
Member

ahze commented Mar 14, 2026

I completely agree that the old process was confusing -- part of the problem was that daemonless-io/scripts/generate_docs.py was built before dbuild even existed and relied on its own disconnected process, that wasn't documented at all...

I’ve just finished a major overhaul of our documentation engine to strip all that away and make the workflow simple as possible, while keeping compose.yaml as the single source of truth.

I’ve added a Contributing Guide that explains the new workflow. To answer your "fix a typo" question, the process is now just as straightforward as your README.template -> update.sh example:

Typos/Metadata: Edit the compose.yaml in the image repo.

Structural changes (like AppJail): Edit the master template in the dbuild repo.

Sync: Run dbuild generate (our new equivalent to your update.sh) to automatically update the repo's README.md.

I've also already ported your AppJail patterns into our central template. It now auto-generates the .env with defaults and uses the !ENV syntax in appjail-director.yml exactly as you suggested to pass those variables to oci.environment. I tested the automated output for Redis on one of my FreeBSD nodes and it worked perfectly, I also tested home-assistant and it worked.

@DtxdF
Copy link
Copy Markdown
Contributor Author

DtxdF commented Mar 15, 2026

Thanks for this!

I'll try it all out later. btw I've updated the dbuild port to the latest version, so I'll make changes later with the most recent code.

@ahze
Copy link
Copy Markdown
Member

ahze commented Mar 15, 2026

Following up on the Redis test, I've just added AppJail support to both Plex and Home Assistant. Everything deployed smoothly using the instructions in the READMEs. Let me know what you think when you have a chance to take a look.

ahze added a commit to daemonless/immich that referenced this pull request Mar 15, 2026
ahze added a commit to daemonless/dbuild that referenced this pull request Mar 16, 2026
@ahze ahze self-assigned this Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants