Hey everyone,
We already have multiple ways of installing Elixir (
https://elixir-lang.org/install.html) but I believe we can still do better. Elixir is cross-platform but Erlang/OTP is not. We need to get OTP for **our OS/architecture**, ideally prebuilt or otherwise we need to compile it from source. I've listed some challenges with existing installation methods here:
https://github.com/erlef/build-and-packaging-wg/issues/80.
Since a few releases ago, Elixir project maintains installer for Windows, e.g. <
https://github.com/elixir-lang/elixir/releases/download/v1.17.2/elixir-otp-27.exe>, but that still requires OTP. The installer tries to be helpful, finds whether OTP is already installed and the version matches and otherwise show a link to download it. This is a GUI installer that fortunately can be running headless, `.\elixir-otp-27.exe /S /D=C:\elixir`, but, again, we need to first install OTP.
I believe we can significantly improve Elixir getting started experience by having a "one click install" but for terminals, download a single script that installs Elixir and OTP for their system.
I've created a proof-of-concept called Elixir Install (
https://elixir-install.org) and we can use it in bash for macOS/Ubuntu/Windows:
$ curl -fsS
https://elixir-install.org/install.sh $ sh install.sh eli...@1.17.2 o...@27.0.1
$ export PATH=$HOME/.elixir-install/installs/otp/27.0.1/bin:$PATH
$ export PATH=$HOME/.elixir-install/installs/elixir/1.17.2-otp-27/bin:$PATH
iex
and Powershell on Windows:
> curl.exe -fsS
https://elixir-install.org/install.bat > .\install.bat eli...@1.17.2 o...@27.0.1
> $env:PATH = "$env:USERPROFILE\.elixir-install\installs\otp\27.0.1\bin;$env:PATH"
> $env:PATH = "$env:USERPROFILE\.elixir-install\installs\elixir\1.17.2-otp-27\bin;$env:PATH"
> iex.bat
(The actual script is .bat because I noticed that even though Windows ships with Powershell, by default running external scripts is prohibited.)
The script can also be executed without arguments, it will install the latest Elixir & OTP (hardcoded inside the script)
$ curl -fsS
https://elixir-install.org/install.sh | sh
downloading
https://github.com/erlef/otp_builds/releases/download/OTP-27.0.1/OTP-27.0.1-macos-arm64.tar.gz downloading
https://github.com/elixir-lang/elixir/releases/download/v1.17.2/elixir-otp-27.zip (...)
The script is downloading OTP from these places:
* macOS: <
https://github.com/erlef/otp_builds/releases/download/OTP-27.0.1/OTP-27.0.1-macos-arm64.tar.gz>, see
https://github.com/erlef/build-and-packaging-wg/issues/80 * Ubuntu: <
https://builds.hex.pm/builds/otp/arm64/ubuntu-22.04/OTP-27.0.1.tar.gz>, see <
https://github.com/hexpm/bob?tab=readme-ov-file#erlang-builds>. In the future I'd like to move it to <
github.com/erlef/otp_builds> too.
* Windows: <
https://github.com/erlang/otp/releases/download/OTP-27.0.1/otp_win64_27.0.1.zip>
I'd like to propose making this official under
elixir-lang.org, that is:
*
https://elixir-lang.org/install.sh *
https://elixir-lang.org/install.bat## Security
In my proof of concept there are no additional security considerations besides using https. If this is not good enough, I think we could use the same security model as `mix local.hex`, that is, we'd download the build, the builds.txt (with all builds and their checksums), and the builds.txt.signed, and verify the signature against the public key the install would ship with. See
https://blog.voltone.net/post/25 for more information.
To have an idea, this would be along the lines of:
curl -fsSO
https://builds.hex.pm/installs/hex-1.x.csv curl -fsSO
https://builds.hex.pm/installs/hex-1.x.csv.signed # run `mix local.public_keys --detailed` and create public_key.pem
openssl dgst -sha256 -verify public_key.pem -signature <(openssl base64 -d -in hex-1.x.csv.signed) hex-1.x.csv
`openssl` is available on macOS, Windows, and Ubuntu Desktop.
## Non-Goals
* No version management along the lines of asdf/mise/etc, this is better solved by these tools anyway.
## Caveats
In my proof of concept, the script requires sh and unzip on UNIX. (On Windows it's using curl too, which is built-in, but can be easily rewritten to using Powershell `Invoke-WebRequest`.) One caveat with this is while this works out of the box on Ubuntu Desktop,
the official Ubuntu Docker images does not have these and so they need to be installed:
$ docker run --rm -it ubuntu bash
docker$ apt update && apt install -y curl unzip
docker$ curl -fsS
https://elixir-install.org/install.sh | sh
This applies to `openssl` mentioned in the security section too. We could solve this by instead of a script have an executable (written in Go/Rust/Zig/etc) that would have everything it needs to download, unpack, and verify things. I think this would complicate things (executable would now or down the road have to be code signed, which fortunately we have some experience with already), users will be presented with a list to pick, and scripts would need a heuristic to figure out which installer to download.
## BEAMup
Tristan Sloughter is working on [BEAMup](
https://erlangforums.com/t/beamup-a-new-way-to-install-erlang-gleam-and-more-to-come/3912), similar tool but way more ambitious and with bigger scope. I'd like to think much smaller scope of
elixir-lang.org/install.sh would make it easier to maintain. The most complicated underlying piece, having prebuilt OTP, is shared between the tools anyway.
## Elixir.app
Brian Cardarella shared a proof-of-concept of a GUI installer for macOS:
https://x.com/bcardarella/status/1831040691801088308. Again, this would have bigger scope and the underlying foundation in prebuilt OTP is shared anyway.