Deploying Applications Using curl
Small teams face several challenges when distributing binaries these days. If you simply put an application up for download on a website, search tools will immediately flag your site as suspicious content. Browsers show the user a scary warning, and there is no way to remove it, even with a signed binary. The warning only goes away once enough users have downloaded your binary without reporting problems.
Letting the user download the binary from some already well-known site, even GitHub, isn’t ideal, especially for closed-source applications.
Packaging the binary to support the many package-management formats across the various Linux distributions is too much work for a small team.
One alternative is to use curl with bash scripts, as in the example below.
curl -fsSL https://example.com | bash
The -fsSL flags silence the output, follow redirects, and use SSL.
- -f: Fail silently on HTTP errors.
- -s: Silence the progress bar.
- -S: When used with -s, show HTTP errors (but not the progress bar).
- -L: Follow location redirects.
This approach isn’t perfect, though. It has several security implications, and many users, especially advanced ones, will turn up their noses at it, and rightly so.
Even with well-intentioned developers, there’s a real chance that a not-quite-perfect bash script will ruin a system that is perfectly configured.
It’s always a good idea to inspect what the install script does before running it.
curl -fsSL https://example.com | less
For the developer, besides making deployment much simpler, it’s also possible to write a script that checks whether the target machine has the required dependencies and tells the user what needs to be installed.
The install script can also detect the architecture and operating system, so the user doesn’t have to worry about which version to install.
Still, there’s always the possibility of failure, and it’s very frustrating for the user when a script fails halfway through, so here are a few tips to get the best results.
Keep your install script small and easy to read, and add relevant comments.
If you need temporary files, always use the
$TMPDIRvariable so you don’t scatter files all over the system.If the user has to do any manual configuration, such as adjusting the PATH, put that in a very clear message at the end of the script’s execution.
The binary you distribute should have as few dependencies as possible, ideally being fully static so it doesn’t depend on anything, not even libc. That way installation is much more likely to succeed and the application to run without problems.
Configuration should live in the appropriate, expected places, such as
.config/application_nameor/etc/application_name, and be well documented.It’s a good idea for the installation to not require superuser permissions to work, but then you need to ask the user where to place the binary and remind them to adjust the PATH variable. If you’d rather have the installation done by a superuser, you can place the binary in
/usr/local/bin, which should already be in the PATH. On one hand this saves the user from having to change the system; on the other, they’re placing a great deal of trust in your work.At the end of the installation, remember to also explain how to remove your program.
Here’s an example of a very basic install script that already detects the operating system and architecture.
#!/bin/bash
# Determine OS, architecture, and download URL
OS=$(uname)
ARCH=$(uname -m)
BASE_URL="https://example.com"
BIN_DIR="/usr/local/bin"
BIN_NAME="appname"
# Prepare the download URL
DOWNLOAD_URL="$BASE_URL/$OS/$ARCH/$BIN_NAME"
# Download and install
echo "Downloading $DOWNLOAD_URL to $BIN_DIR/$BIN_NAME"
curl -sSL $DOWNLOAD_URL -o $BIN_DIR/$BIN_NAME
if [ $? -ne 0 ]; then
echo "Failed to install $BIN_NAME"
exit 1
fi
chmod +x $BIN_DIR/$BIN_NAME
echo "Installed $BIN_NAME to $BIN_DIR/$BIN_NAME"
What we can conclude is that this isn’t the ideal way to distribute software, but it’s undoubtedly one of the least problematic, especially if your users have some technical knowledge.