Skip to content

Repository files navigation

GURL

When CURL says your SSL library is too old — use GURL.

One file. Zero SSL dependencies.

GURL

HTTP HTTPS TLS Dependencies Cross Platform

Go Report Card Go Reference Quality Coverage Status License: GPL v3


Common Problems Solved by GURL

These are typical situations where GURL is useful:

  • I need to download one file but curl is not installed.
  • I need HTTPS but OpenSSL is unavailable.
  • I need a standalone HTTP client with no external runtime dependencies.
  • I need an HTTP client for an old or unusual operating system.
  • I need the same command-line utility on Linux, BSD, macOS, and Windows.
  • I need a curl-like utility compiled with TLS support already included.

That's what GURL is for.

One binary.
No external libraries.
HTTP and HTTPS.
Runs on a lot of platforms.


What is GURL?

GURL is a small, standalone command-line HTTP/HTTPS client written in Go.

It is designed for situations where you just need to download a new software on an old system, call an HTTPS endpoint, send POST data, or make a simple request — without installing curl, OpenSSL, or a collection of shared libraries.

TLS support is built into the binary through Go's standard library. GURL also embeds the Mozilla CA bundle published by curl, so certificate verification does not depend on an old or missing CA store on the host operating system.

This makes GURL especially useful for:

  • installing new software on old operating systems
  • servers where curl or OpenSSL is unavailable or outdated

Just download one executable and run it.

gurl https://example.com

If no protocol is specified, GURL uses http://:

gurl example.com

Universal installer / Универсальная установка
auto-detect OS/ARCH · root → /bin · user → ~/.local/bin

For Unix-like systems you can use one bootstrap installer.

It detects the operating system and CPU architecture, downloads the correct GURL binary using an available native downloader, and selects the installation path automatically:

  • if the installer runs as root/bin/gurl
  • if it runs as a normal user → ~/.local/bin/gurl

After installation it immediately prints ready-to-copy examples showing how to run GURL.

Install

Normal user:

sh install-gurl.sh

System-wide:

sudo sh install-gurl.sh

install-gurl.sh

#!/bin/sh

set -u

BASE_URL="${GURL_BASE_URL:-http://files.zabiyaka.net/gurl/latest}"

have() {
    command -v "$1" >/dev/null 2>&1
}

die() {
    echo "gurl-install: $*" >&2
    exit 1
}

say() {
    echo "gurl-install: $*"
}

# Detect OS

UNAME_S="$(uname -s 2>/dev/null || echo unknown)"

case "$UNAME_S" in
    Linux)
        if [ -n "${ANDROID_ROOT:-}" ] ||
           [ -n "${ANDROID_DATA:-}" ] ||
           [ -n "${TERMUX_VERSION:-}" ]; then
            OS="android"
        else
            OS="linux"
        fi
        ;;
    Darwin) OS="mac" ;;
    FreeBSD) OS="freebsd" ;;
    OpenBSD) OS="openbsd" ;;
    NetBSD) OS="netbsd" ;;
    DragonFly) OS="dragonfly" ;;
    SunOS)
        SUN_VERSION="$(uname -v 2>/dev/null || true)"
        if echo "$SUN_VERSION" | grep -i illumos >/dev/null 2>&1; then
            OS="illumos"
        elif [ -r /etc/release ] &&
             grep -Ei 'illumos|OpenIndiana|OmniOS|SmartOS' /etc/release >/dev/null 2>&1; then
            OS="illumos"
        else
            OS="solaris"
        fi
        ;;
    AIX) OS="aix" ;;
    *) die "unsupported operating system: $UNAME_S" ;;
esac

# Detect architecture

if [ "$OS" = "aix" ]; then
    ARCH="ppc64"
else
    UNAME_M="$(uname -m 2>/dev/null || echo unknown)"

    case "$UNAME_M" in
        x86_64|amd64) ARCH="amd64" ;;
        i386|i486|i586|i686|x86) ARCH="386" ;;
        aarch64|arm64) ARCH="arm64" ;;
        armv4*|armv5*|armv6*|armv7*|armv8l|arm) ARCH="arm" ;;
        loongarch64|loong64) ARCH="loong64" ;;
        mips64el|mips64le) ARCH="mips64le" ;;
        mips64) ARCH="mips64" ;;
        mipsel|mipsle) ARCH="mipsle" ;;
        mips) ARCH="mips" ;;
        ppc64le|powerpc64le) ARCH="ppc64le" ;;
        ppc64|powerpc64) ARCH="ppc64" ;;
        riscv64) ARCH="riscv64" ;;
        s390x) ARCH="s390x" ;;
        *) die "unsupported CPU architecture: $UNAME_M" ;;
    esac
fi

# Verify that this build exists

case "$OS/$ARCH" in
    linux/amd64|linux/arm64|linux/386|linux/arm|linux/loong64|\
    linux/mips|linux/mipsle|linux/mips64|linux/mips64le|\
    linux/ppc64|linux/ppc64le|linux/riscv64|linux/s390x|\
    mac/amd64|mac/arm64|\
    freebsd/amd64|freebsd/arm64|freebsd/386|freebsd/arm|freebsd/riscv64|\
    openbsd/amd64|openbsd/arm64|openbsd/386|openbsd/arm|openbsd/ppc64|openbsd/riscv64|\
    android/arm64|\
    netbsd/amd64|netbsd/386|netbsd/arm|netbsd/arm64|\
    solaris/amd64|illumos/amd64|dragonfly/amd64|aix/ppc64)
        ;;
    *) die "GURL binary is not available for $OS/$ARCH" ;;
esac

URL="$BASE_URL/$OS/$ARCH/gurl"

say "detected platform: $OS/$ARCH"
say "download: $URL"

# Temporary directory

TMPBASE="${TMPDIR:-/tmp}"
TMP="$TMPBASE/gurl-install.$$"
DOWNLOAD="$TMP/gurl"

umask 077
mkdir "$TMP" 2>/dev/null || die "cannot create temporary directory: $TMP"

cleanup() {
    rm -rf "$TMP" >/dev/null 2>&1 || true
}

trap cleanup EXIT HUP INT TERM

# Download using the most suitable available tool

download() {
    if [ "$OS" = "freebsd" ] || [ "$OS" = "dragonfly" ]; then
        if have fetch; then
            say "using fetch"
            fetch -o "$DOWNLOAD" "$URL" && return 0
        fi
    fi

    if [ "$OS" = "openbsd" ] || [ "$OS" = "netbsd" ]; then
        if have ftp; then
            say "using ftp"
            ftp -o "$DOWNLOAD" "$URL" && return 0
        fi
    fi

    if [ -x /usr/sfw/bin/wget ]; then
        say "using /usr/sfw/bin/wget"
        /usr/sfw/bin/wget -O "$DOWNLOAD" "$URL" && return 0
    fi

    if have wget; then
        say "using wget"
        wget -O "$DOWNLOAD" "$URL" && return 0
    fi

    if have busybox && busybox wget --help >/dev/null 2>&1; then
        say "using BusyBox wget"
        busybox wget -O "$DOWNLOAD" "$URL" && return 0
    fi

    if have toybox && toybox wget --help >/dev/null 2>&1; then
        say "using Toybox wget"
        toybox wget -O "$DOWNLOAD" "$URL" && return 0
    fi

    if have curl; then
        say "using curl"
        curl -fL -o "$DOWNLOAD" "$URL" && return 0
    fi

    die "no usable HTTP downloader found.

Tried:
  fetch
  ftp
  wget
  /usr/sfw/bin/wget
  BusyBox wget
  Toybox wget
  curl

Direct URL:
  $URL"
}

download

[ -s "$DOWNLOAD" ] || die "downloaded file is empty"

chmod 755 "$DOWNLOAD" || die "cannot make downloaded GURL executable"

# Root -> /bin, normal user -> ~/.local/bin

IS_ROOT=0

if have id && [ "$(id -u 2>/dev/null)" = "0" ]; then
    IS_ROOT=1
fi

if [ "$IS_ROOT" = "1" ]; then
    DESTDIR="/bin"
else
    [ -n "${HOME:-}" ] || die "HOME is not defined"
    DESTDIR="$HOME/.local/bin"
fi

DEST="$DESTDIR/gurl"

mkdir -p "$DESTDIR" || die "cannot create $DESTDIR"
cp "$DOWNLOAD" "$DEST" || die "cannot install $DEST"
chmod 755 "$DEST" || die "cannot chmod $DEST"

say "installed: $DEST"

"$DEST" -V || die "GURL was installed, but version test failed"

# Print immediate help

echo
echo "============================================================"
echo "GURL is ready"
echo "============================================================"
echo
echo "Installed:"
echo "  $DEST"
echo
echo "Try it now:"
echo
echo "  $DEST https://example.com"
echo
echo "Download a file:"
echo
echo "  $DEST -o file.zip https://example.com/file.zip"
echo

if [ "$IS_ROOT" = "1" ]; then
    echo "System-wide command:"
    echo
    echo "  gurl https://example.com"
else
    case ":${PATH:-}:" in
        *":$DESTDIR:"*)
            echo "GURL is already in your PATH."
            echo
            echo "Run:"
            echo
            echo "  gurl https://example.com"
            ;;
        *)
            echo "$DESTDIR is not in your PATH yet."
            echo
            echo "For this shell, run:"
            echo
            echo "  export PATH=\"$DESTDIR:\$PATH\""
            echo
            echo "Then:"
            echo
            echo "  gurl https://example.com"
            echo
            echo "To make it permanent, add the export line to your shell profile."
            ;;
    esac
fi

echo
echo "Help:"
echo "  gurl --help"
echo
echo "Version:"
echo "  gurl -V"
echo


Downloads / Скачать

Choose your platform and architecture below.

The binary URLs intentionally use HTTP. This is the bootstrap path for old or minimal systems where HTTPS tools, CA certificates, OpenSSL, or the installed TLS stack may be unavailable or obsolete. After downloading GURL, use GURL itself for HTTPS.

Linux Linux
amd64 / arm64 / 386 / ARM / LoongArch / MIPS / PPC64 / RISC-V / s390x

amd64 / x86_64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/amd64/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/amd64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/amd64/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

arm64 / aarch64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/arm64/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/arm64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/arm64/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

386 / x86

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/386/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/386/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/386/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

ARM

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/arm/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/arm/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/arm/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

LoongArch 64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/loong64/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/loong64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/loong64/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

MIPS

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

MIPS little-endian

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mipsle/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mipsle/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mipsle/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

MIPS64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips64/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips64/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

MIPS64 little-endian

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips64le/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips64le/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/mips64le/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

PowerPC 64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/ppc64/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/ppc64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/ppc64/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

PowerPC 64 little-endian

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/ppc64le/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/ppc64le/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/ppc64le/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

RISC-V 64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/riscv64/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/riscv64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/riscv64/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

IBM s390x

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/s390x/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/linux/s390x/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/linux/s390x/gurl; else echo 'No HTTP downloader found (wget, BusyBox wget, or curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

macOS macOS
Intel / Apple Silicon

Intel / amd64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; /usr/bin/curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/mac/amd64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

Apple Silicon / arm64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; /usr/bin/curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/mac/arm64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

Windows Windows
amd64 / arm64 / 386 / ARM

The command uses System.Net.WebClient, which works with older Windows PowerShell versions and does not require Invoke-WebRequest.

amd64 / x86_64

download

(New-Object System.Net.WebClient).DownloadFile("http://files.zabiyaka.net/gurl/latest/windows/amd64/gurl.exe", "$PWD\gurl.exe"); .\gurl.exe -V

arm64

download

(New-Object System.Net.WebClient).DownloadFile("http://files.zabiyaka.net/gurl/latest/windows/arm64/gurl.exe", "$PWD\gurl.exe"); .\gurl.exe -V

386 / x86

download

(New-Object System.Net.WebClient).DownloadFile("http://files.zabiyaka.net/gurl/latest/windows/386/gurl.exe", "$PWD\gurl.exe"); .\gurl.exe -V

ARM

download

(New-Object System.Net.WebClient).DownloadFile("http://files.zabiyaka.net/gurl/latest/windows/arm/gurl.exe", "$PWD\gurl.exe"); .\gurl.exe -V

FreeBSD FreeBSD
amd64 / arm64 / 386 / ARM / RISC-V

amd64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; fetch -o "$DEST" http://files.zabiyaka.net/gurl/latest/freebsd/amd64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

arm64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; fetch -o "$DEST" http://files.zabiyaka.net/gurl/latest/freebsd/arm64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

386

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; fetch -o "$DEST" http://files.zabiyaka.net/gurl/latest/freebsd/386/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

ARM

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; fetch -o "$DEST" http://files.zabiyaka.net/gurl/latest/freebsd/arm/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

RISC-V 64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; fetch -o "$DEST" http://files.zabiyaka.net/gurl/latest/freebsd/riscv64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

OpenBSD OpenBSD
amd64 / arm64 / 386 / ARM / PPC64 / RISC-V

amd64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/openbsd/amd64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

arm64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/openbsd/arm64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

386

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/openbsd/386/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

ARM

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/openbsd/arm/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

PowerPC 64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/openbsd/ppc64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

RISC-V 64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/openbsd/riscv64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

Android
arm64

arm64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/android/arm64/gurl; elif command -v toybox >/dev/null 2>&1; then toybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/android/arm64/gurl; elif command -v busybox >/dev/null 2>&1; then busybox wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/android/arm64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/android/arm64/gurl; else echo 'No HTTP downloader found (wget/Toybox/BusyBox/curl).' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

NetBSD
amd64 / 386 / ARM / arm64

amd64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/netbsd/amd64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

386

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/netbsd/386/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

ARM

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/netbsd/arm/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

arm64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; ftp -o "$DEST" http://files.zabiyaka.net/gurl/latest/netbsd/arm64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

Solaris
amd64

amd64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/solaris/amd64/gurl; elif [ -x /usr/sfw/bin/wget ]; then /usr/sfw/bin/wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/solaris/amd64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/solaris/amd64/gurl; else echo 'No HTTP downloader found. Install/copy wget or curl, or use the direct download link above.' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

Plan 9
amd64 / 386 / ARM

Uses Plan 9 hget, whose native purpose is retrieving HTTP URLs.

amd64

download

hget http://files.zabiyaka.net/gurl/latest/plan9/amd64/gurl >gurl
./gurl -V

386

download

hget http://files.zabiyaka.net/gurl/latest/plan9/386/gurl >gurl
./gurl -V

ARM

download

hget http://files.zabiyaka.net/gurl/latest/plan9/arm/gurl >gurl
./gurl -V

Illumos
amd64

amd64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/illumos/amd64/gurl; elif [ -x /usr/sfw/bin/wget ]; then /usr/sfw/bin/wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/illumos/amd64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/illumos/amd64/gurl; else echo 'No HTTP downloader found. Install/copy wget or curl, or use the direct download link above.' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

DragonFly BSD
amd64

amd64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; fetch -o "$DEST" http://files.zabiyaka.net/gurl/latest/dragonfly/amd64/gurl && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

AIX
ppc64

AIX base ftp speaks FTP, not HTTP. Because the GURL bootstrap server here is HTTP, a bare AIX installation needs an available HTTP downloader (wget/curl) or the binary copied from another machine.

PowerPC 64

download

if [ "$(id -u 2>/dev/null)" = "0" ]; then DESTDIR="/bin"; else DESTDIR="$HOME/.local/bin"; fi; mkdir -p "$DESTDIR"; DEST="$DESTDIR/gurl"; if command -v wget >/dev/null 2>&1; then wget -O "$DEST" http://files.zabiyaka.net/gurl/latest/aix/ppc64/gurl; elif command -v curl >/dev/null 2>&1; then curl -fL -o "$DEST" http://files.zabiyaka.net/gurl/latest/aix/ppc64/gurl; else echo 'Base AIX ftp does not fetch HTTP URLs. Copy/install wget or curl, or use the direct download link above.' >&2; exit 1; fi && chmod 755 "$DEST" && "$DEST" -V && echo && echo "GURL installed: $DEST" && echo "Run: $DEST https://example.com"

Usage / Как пользоваться

Basic syntax:

gurl [options] <URL>

Simple GET request:

gurl https://example.com

A URL without a scheme automatically uses HTTP:

gurl example.com

Equivalent to:

gurl http://example.com

Examples / Примеры

Download a file

gurl -o file.zip https://example.com/file.zip

or:

gurl --output file.zip https://example.com/file.zip

Use GURL in shell scripts

gurl https://example.com/script.sh | bash

POST data

gurl -d "key=value&key2=value2" https://example.com

or:

gurl --data "key=value&key2=value2" https://example.com

When -d / --data is used, GURL automatically performs a POST request.


Send JSON

gurl -H "Content-Type: application/json" -d '{"key":"value"}' https://example.com/api

Multipart form

Text fields and files can be supplied in one -F argument separated by &:

gurl -F "name=test&file=@/tmp/file.txt" https://example.com/upload

Custom HTTP method

gurl -X DELETE https://example.com/api/item
gurl -X PUT https://example.com/api/item

Custom header

gurl -H "Authorization: Bearer TOKEN" https://example.com/api

or:

gurl --header "Authorization: Bearer TOKEN" https://example.com/api

Cookies

gurl -b "session_id=abc123" https://example.com

or:

gurl --cookie "session_id=abc123" https://example.com

HEAD request

gurl -I https://example.com

or:

gurl --head https://example.com

Custom User-Agent

gurl -A "MyClient/1.0" https://example.com

or:

gurl --user-agent "MyClient/1.0" https://example.com

Timeout

gurl -m 10 https://example.com

or:

gurl --connect-timeout 10 https://example.com

-m / --max-time limits the complete transfer. --connect-timeout limits connection establishment. Values use curl-compatible seconds and may be fractional. There is no total transfer timeout by default.


Ignore TLS certificate verification

Useful for self-signed certificates:

gurl -k https://192.168.1.1

or:

gurl --unsafe https://192.168.1.1

Warning: disabling certificate verification reduces connection security.


Fail on HTTP errors

gurl --fail https://example.com/not-found

For HTTP status 400 and above, GURL exits with error code 22.

This is useful in shell scripts:

gurl --fail https://example.com/file || echo "Download failed"

Redirects

Like curl, GURL does not follow HTTP redirects by default. Use -L when the redirect target should be requested:

gurl -L https://example.com

Show version

gurl -V

or:

gurl --version

Flags / Флаги

-s, --silent                    silent mode
-D, --dump-header <file>        write received headers to a file
-4, --ipv4                      use IPv4 only
-6, --ipv6                      use IPv6 only
-L, --location                  follow redirects
    --trace-ascii <file>        write an ASCII request/response trace
    --capath <directory>        use certificates from a CA directory
    --cacert <file>             use a CA certificate bundle
-g, --globoff                   disable URL globbing (GURL never expands it)
-k, --insecure                  disable TLS certificate verification
-I, --head                      perform a HEAD request and print headers
-A, --user-agent <name>        set User-Agent
-X, --request <method>          set the HTTP method
-H, --header <header>           add a header; may be repeated
-d, --data <contents>           send request data; may be repeated
    --connect-timeout <seconds> limit DNS, TCP, and TLS connection time
-m, --max-time <seconds>        limit the complete transfer
-o, --output <file>             save the response body
-f, --fail                      return exit code 22 for HTTP errors
-F, --form <field>              send a multipart field or field=@file
-b, --cookie <cookies>          send the Cookie header
-V, --version                   show GURL version

The historical --useragent, --unsafe, and duration-based --timeout names remain available for existing GURL scripts. Curl-compatible names should be used in new scripts.


Replacing curl for acme.sh

GURL accepts the complete curl option set emitted by acme.sh 3.1.5. The binary may be copied or linked under the name curl; no wrapper or argument translation is required:

install -m 0755 gurl /usr/local/bin/curl
curl --silent --dump-header /root/.acme.sh/http.header -L \
  --connect-timeout 10 --user-agent 'acme.sh/3.1.5' \
  -H '' https://acme.zerossl.com/v2/DV90

The embedded CA file is the Mozilla bundle published at https://curl.se/docs/caextract.html, revision 2026-08-13, SHA-256 f66dff1bdf8f96060b8177976f8b7d9254bc89bc4db933d769f7384d28480bc9. It is distributed under MPL 2.0. --cacert or --capath replaces the embedded trust roots for that invocation. --insecure remains explicit and should only be used for controlled diagnostics.

To update the built-in roots, download a new cacert.pem from that source into pkg/certificates, verify it against the published .sha256 file, then update the pinned checksum and root count in pkg/certificates/certificates_test.go and this section. Run go test ./... before publishing binaries.


Build from source

Clone the repository:

git clone https://github.com/matveynator/gurl.git
cd gurl

Build:

go build -o gurl gurl.go

Run:

./gurl https://example.com

Test

Run the complete test suite, race detector, and coverage report:

go test -count=1 -race -coverprofile=coverage.out ./...
go tool cover -func=coverage.out

The same checks run in GitHub Actions. Coverage reports are published to Coveralls.

Release binaries can be cross-compiled with the standalone release utility:

go run scripts/crosscompile/crosscompile.go

License

GURL is distributed under the GNU General Public License v3.0. The embedded Mozilla CA bundle is separately distributed under MPL 2.0.


Source

https://github.com/matveynator/gurl

Contributions and fixes are welcome.