Skip to content

patmaddox/ex_freebsd

Repository files navigation

ExFreeBSD

Helping Elixir mix releases become FreeBSD packages, since 2022.

Documentation: https://hexdocs.pm/freebsd

Installation

You DO need elixir to build your release and package. You can install it with pkg install elixir. (See Choosing an OTP Version below).

You DO NOT need elixir to run your app, assuming your mix release configures include_erts: true (which is the default).

Add freebsd to your list of dependencies in mix.exs:

def deps do
  [
    {:freebsd, "~> 0.6.0", runtime: false}
  ]
end

Add a freebsd key to mix.exs project config.

  def project do
    [
      # ExFreeBSD requires these standard keys:
      app: :freebsd,
      version: "0.0.0",
      description: description(),
      homepage_url: "https://github.com/patmaddox/ex_freebsd",
      # and adds this one:
      freebsd: freebsd()
    ]
  end

  defp freebsd do
    %{
      # required
      maintainer: "[email protected]",
      description: description(), # can be a multi-line string instead
      user: "service-username", # optional - user will be created automatically

      # optional, documented at https://www.freebsd.org/cgi/man.cgi?pkg-create(8)
      deps: %{
        bash: %{version: "5.1", origin: "shells/bash"}
      }
    }
  end

Usage

Build a release as usual: env MIX_ENV=prod mix release --overwrite

env MIX_ENV=prod mix freebsd.pkg will produce a FreeBSD .pkg file which you can then install as usual.

ExFreeBSD produces /usr/local/etc/rc.d/<appname> which provides the following commands:

  • start
  • stop
  • restart
  • status
  • remote

Run them using service(8).

After installing the package, you can define application-specific environment variables in /usr/local/etc/<appname>/<appname>.env:

DATABASE_URL=ecto://user:password@host/db
AWS_ACCESS_KEY_ID=abc123def456

Logs go to /var/log/<appname>.log. Crash dumps default to /var/log/<appname>_erl_crash.dump. Any additional temp app data defaults to /var/run/<appname>.

Choosing an OTP Version

The simplest way to install and build with elixir is to pkg install elixir. This will use the most recently built lang/elixir and lang/erlang ports.

If you want to use a more recent version of elixir, and specify your erlang/OTP version, you should install lang/elixir-devel and the elixir-runtime* you want.

The key difference between lang/erlang and lang/erlang-runtime* is that lang/erlang installs the erlang tools to /usr/local/bin, and lang/erlang-runtime* do not. This means that you will explicitly need to add the package's bin path to your PATH to use the tools, e.g. export PATH=/usr/local/lib/erlang25/bin:$PATH.

See .cirrus.yml for an example of how to install and configure a specific erlang runtime. (Note that PATH is set using Cirrus CI's env var syntax.)

Roadmap

  • auto-name package w/ CI suffix: <app>-ci-<branch>-<version>p<timestamp>
  • MANIFEST conflict for <app> <app>-ci-*
  • run as non-privileged user
  • document epmd usage (run it as a service, not automatically by package)
  • build package as part of a release