Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ jobs:
bash -n amneziawg-web/scripts/amneziawg-web-uninstall.sh
bash -n amneziawg-web/scripts/amneziawg-web-upgrade.sh
bash -n amneziawg-proxy.sh
bash -n scripts/amneziawg-cargo-build.sh
bash -n amneziawg-proxy/scripts/amneziawg-proxy-common.sh
bash -n amneziawg-proxy/scripts/amneziawg-proxy-install.sh
bash -n amneziawg-proxy/scripts/amneziawg-proxy-uninstall.sh
bash -n amneziawg-proxy/scripts/amneziawg-proxy-upgrade.sh
bash -n tests/test-cargo-build-common.sh
bash -n tests/test-proxy-bootstrap.sh
bash -n tests/test-ubuntu-ppa.sh
bash -n tests/test-ubuntu-resolute-live.sh
bash -n tests/test-install-mock.sh
Expand All @@ -45,8 +49,12 @@ jobs:
shellcheck --severity=warning amneziawg-web/scripts/amneziawg-web-uninstall.sh
shellcheck --severity=warning amneziawg-web/scripts/amneziawg-web-upgrade.sh
shellcheck --severity=warning amneziawg-proxy.sh
shellcheck --severity=warning scripts/amneziawg-cargo-build.sh
shellcheck --severity=warning amneziawg-proxy/scripts/amneziawg-proxy-common.sh
shellcheck --severity=warning amneziawg-proxy/scripts/amneziawg-proxy-install.sh
shellcheck --severity=warning amneziawg-proxy/scripts/amneziawg-proxy-uninstall.sh
shellcheck --severity=warning amneziawg-proxy/scripts/amneziawg-proxy-upgrade.sh
shellcheck --severity=warning tests/test-cargo-build-common.sh
shellcheck --severity=warning tests/test-proxy-bootstrap.sh
shellcheck --severity=warning tests/test-ubuntu-ppa.sh
shellcheck --severity=warning tests/test-ubuntu-resolute-live.sh
4 changes: 4 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ jobs:
- name: Run unit tests
run: |
bash tests/test-functions.sh
bash tests/test-cargo-build-common.sh
bash tests/test-ubuntu-ppa.sh
bash tests/test-proxy-scripts.sh
sudo bash tests/test-proxy-bootstrap.sh

- name: Run proxy Rust tests
working-directory: amneziawg-proxy
Expand Down Expand Up @@ -79,6 +81,8 @@ jobs:
run: |
bash -n amneziawg-install.sh
bash -n amneziawg-web.sh
bash -n amneziawg-proxy.sh
bash -n scripts/amneziawg-cargo-build.sh

- name: Run integration test in Docker
run: |
Expand Down
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,24 @@ Temporarily disabled:

Reason: verified AmneziaWG 2.0 packages are not currently available for these RPM-based distributions. Please watch this repository's releases and README for support status updates.

2 GB of free space required for temporary build files.
Source builds require approximately 2 GiB of free space for `amneziawg-web`
and 1 GiB for `amneziawg-proxy`. Their install and upgrade scripts inspect the
Cargo target filesystem, free inodes, CPU count, and available memory before
building. On constrained hosts they use one Cargo job and, when the source
filesystem is too small, place build artifacts on a suitable disk-backed
filesystem automatically.

To select a specific build filesystem, create a writable directory on an
executable mount and pass it explicitly:

```bash
sudo env AMNEZIAWG_BUILD_ROOT=/path/with/free-space ./amneziawg-web.sh upgrade
sudo env AMNEZIAWG_BUILD_ROOT=/path/with/free-space ./amneziawg-proxy.sh upgrade
```

An explicit `CARGO_TARGET_DIR` is also supported, but is treated as strict: the
operation fails with a diagnostic if that target does not meet the build
requirements.

---

Expand Down
87 changes: 83 additions & 4 deletions amneziawg-proxy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ readonly REPO_REF="main"
SCRIPT_DIR="$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
SCRIPTS_DIR="${SCRIPT_DIR}/amneziawg-proxy/scripts"
BOOTSTRAP_DIR=""
BOOTSTRAP_TMPDIR=""

INSTALLER="${SCRIPTS_DIR}/amneziawg-proxy-install.sh"
UPGRADER="${SCRIPTS_DIR}/amneziawg-proxy-upgrade.sh"
Expand Down Expand Up @@ -111,8 +112,34 @@ install_git() {

# ── Bootstrap ────────────────────────────────────────────────────────────────

create_bootstrap_dir() {
Comment thread
wiresock marked this conversation as resolved.
local bootstrap_root="$1"
local requires_exec="$2"
local exec_probe

[[ -d "${bootstrap_root}" ]] && [[ -w "${bootstrap_root}" ]] || return 1
bootstrap_root="$(CDPATH='' cd -- "${bootstrap_root}" 2>/dev/null && pwd -P)" || return 1
BOOTSTRAP_DIR="$(mktemp -d "${bootstrap_root%/}/amneziawg-install.XXXXXX")" || return 1
if [[ "${requires_exec}" -ne 1 ]]; then
return 0
fi

exec_probe="${BOOTSTRAP_DIR}/.exec-probe"
if printf '%s\n' '#!/bin/sh' 'exit 0' > "${exec_probe}" && \
chmod 700 "${exec_probe}" && \
"${exec_probe}" >/dev/null 2>&1 && \
rm -f "${exec_probe}"; then
return 0
fi

rm -rf "${BOOTSTRAP_DIR}"
BOOTSTRAP_DIR=""
return 1
}

bootstrap_repo_if_needed() {
local target_script="$1"
local requires_exec="${2:-1}"
if [[ -f "${target_script}" ]]; then
return 0
fi
Expand All @@ -125,7 +152,42 @@ bootstrap_repo_if_needed() {
fi
fi

BOOTSTRAP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/amneziawg-install.XXXXXX")"
local bootstrap_root existing_root root_seen
local -a bootstrap_roots=()
local -a tried_roots=()
if [[ -n "${AMNEZIAWG_BUILD_ROOT:-}" ]]; then
bootstrap_roots+=("${AMNEZIAWG_BUILD_ROOT}")
fi
if [[ -n "${TMPDIR:-}" ]]; then
bootstrap_roots+=("${TMPDIR}")
fi
bootstrap_roots+=("/var/tmp" "/tmp")

for bootstrap_root in "${bootstrap_roots[@]}"; do
root_seen=0
for existing_root in "${tried_roots[@]}"; do
if [[ "${existing_root}" == "${bootstrap_root}" ]]; then
root_seen=1
break
fi
done
[[ "${root_seen}" -eq 1 ]] && continue
tried_roots+=("${bootstrap_root}")
if create_bootstrap_dir "${bootstrap_root}" "${requires_exec}"; then
break
fi
done

if [[ -z "${BOOTSTRAP_DIR}" ]]; then
if [[ "${requires_exec}" -eq 1 ]]; then
echo "ERROR: No writable temporary filesystem permitting direct execution is available." >&2
echo " Set TMPDIR to an executable filesystem with sufficient free space." >&2
else
echo "ERROR: No writable temporary filesystem is available." >&2
echo " Set TMPDIR to a filesystem with sufficient free space." >&2
fi
exit 1
fi

echo "Required scripts not found locally. Cloning ${REPO_URL} (${REPO_REF}) into ${BOOTSTRAP_DIR} ..." >&2
if ! GIT_TERMINAL_PROMPT=0 git clone --depth 1 --branch "${REPO_REF}" "${REPO_URL}" "${BOOTSTRAP_DIR}" >&2; then
Expand All @@ -134,6 +196,8 @@ bootstrap_repo_if_needed() {
exit 1
fi

BOOTSTRAP_TMPDIR="${BOOTSTRAP_DIR}/.tmp"
mkdir -p "${BOOTSTRAP_TMPDIR}"
SCRIPTS_DIR="${BOOTSTRAP_DIR}/amneziawg-proxy/scripts"
INSTALLER="${SCRIPTS_DIR}/amneziawg-proxy-install.sh"
UPGRADER="${SCRIPTS_DIR}/amneziawg-proxy-upgrade.sh"
Expand Down Expand Up @@ -213,13 +277,28 @@ EOF
run_script() {
local target_var="$1"
shift
local requires_exec=1
local caller_tmpdir
if [[ "${target_var}" == "UNINSTALLER" ]]; then
requires_exec=0
fi

if [[ -n "${TMPDIR:-}" ]] && \
caller_tmpdir="$(CDPATH='' cd -- "${TMPDIR}" 2>/dev/null && pwd -P)"; then
TMPDIR="${caller_tmpdir}"
export TMPDIR
fi

local target="${!target_var}"
bootstrap_repo_if_needed "${target}"
bootstrap_repo_if_needed "${target}" "${requires_exec}"
target="${!target_var}"

local rc=0
bash "${target}" "$@" || rc=$?
if [[ -n "${BOOTSTRAP_TMPDIR}" ]]; then
TMPDIR="${BOOTSTRAP_TMPDIR}" bash "${target}" "$@" || rc=$?
else
bash "${target}" "$@" || rc=$?
fi
exit "${rc}"
}

Expand Down Expand Up @@ -277,7 +356,7 @@ manage_menu() {
run_script INSTALLER
;;
5)
bootstrap_repo_if_needed "${UNINSTALLER}"
bootstrap_repo_if_needed "${UNINSTALLER}" 0

echo ""
echo "Uninstall options:"
Expand Down
7 changes: 7 additions & 0 deletions amneziawg-proxy/doc/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
- **AmneziaWG** already installed and a working `awg0` interface
- **Rust toolchain ≥ 1.75** (only needed for a source build; the installer
can install it automatically via `rustup`)
- Approximately **1 GiB of free build space** when compiling from source

The installer and upgrader inspect available disk space, inodes, CPUs, and
memory before starting Cargo. They automatically use one build job on a
constrained host and can move Cargo artifacts away from a small `/tmp`. Set
`AMNEZIAWG_BUILD_ROOT` to an existing writable directory on an executable
filesystem to choose the build disk explicitly.

---

Expand Down
12 changes: 11 additions & 1 deletion amneziawg-proxy/scripts/amneziawg-proxy-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,18 @@ readonly DEFAULT_RATE_LIMIT="5"
readonly DEFAULT_PROBE_REPLY_BYTES="32768"
readonly DEFAULT_DNS_UPSTREAM="1.1.1.1:53"
readonly DEFAULT_QUIC_DOMAIN="cloudflare.com"
readonly BUILD_MIN_FREE_KB="1048576"

# Script location (for finding the service unit file relative to the repo)
SCRIPT_DIR="$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"

# Source shared helpers (validate_params_file, etc.)
# shellcheck source=amneziawg-proxy-common.sh
. "${SCRIPT_DIR}/amneziawg-proxy-common.sh"
# shellcheck source=../../scripts/amneziawg-cargo-build.sh
. "${SCRIPT_DIR}/../../scripts/amneziawg-cargo-build.sh"

trap awg_cleanup_cargo_build EXIT

# ── Colours ───────────────────────────────────────────────────────────────────

Expand Down Expand Up @@ -446,6 +451,10 @@ Expected the amneziawg-proxy Rust crate directory."

ensure_rust_toolchain

if ! awg_prepare_cargo_build "${SOURCE_DIR}" "amneziawg-proxy" "${BUILD_MIN_FREE_KB}"; then
die "No suitable build environment is available for amneziawg-proxy."
fi

info "Building in: ${SOURCE_DIR}"
info "Running: cargo build --release --locked"

Expand All @@ -454,7 +463,8 @@ Expected the amneziawg-proxy Rust crate directory."
Ensure build dependencies are installed (gcc, pkg-config, libssl-dev or equivalent)."
fi

local built_binary="${SOURCE_DIR}/target/release/amneziawg-proxy"
local built_binary
built_binary="$(awg_cargo_release_binary "amneziawg-proxy")"
if [[ ! -f "${built_binary}" ]]; then
die "Build completed but binary not found at: ${built_binary}"
fi
Expand Down
13 changes: 12 additions & 1 deletion amneziawg-proxy/scripts/amneziawg-proxy-upgrade.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ readonly DEFAULT_INSTALL_DIR="/usr/local/bin"
readonly DEFAULT_CONFIG_FILE="/etc/amneziawg-proxy/proxy.toml"
readonly DEFAULT_DATA_DIR="/var/lib/amneziawg-proxy"
readonly BINARY_NAME="amneziawg-proxy"
readonly BUILD_MIN_FREE_KB="1048576"

SCRIPT_DIR="$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"

# shellcheck source=../../scripts/amneziawg-cargo-build.sh
. "${SCRIPT_DIR}/../../scripts/amneziawg-cargo-build.sh"

trap awg_cleanup_cargo_build EXIT

# -- Defaults -----------------------------------------------------------------

INSTALL_DIR="${DEFAULT_INSTALL_DIR}"
Expand Down Expand Up @@ -303,6 +309,10 @@ Expected the amneziawg-proxy Rust crate directory."

ensure_rust_toolchain

if ! awg_prepare_cargo_build "${SOURCE_DIR}" "amneziawg-proxy" "${BUILD_MIN_FREE_KB}"; then
die "No suitable build environment is available for amneziawg-proxy."
fi

info "Building in: ${SOURCE_DIR}"
info "Running: cargo build --release --locked"

Expand All @@ -311,7 +321,8 @@ Expected the amneziawg-proxy Rust crate directory."
Ensure build dependencies are installed (gcc, pkg-config, libssl-dev or equivalent)."
fi

local built_binary="${SOURCE_DIR}/target/release/${BINARY_NAME}"
local built_binary
built_binary="$(awg_cargo_release_binary "${BINARY_NAME}")"
if [[ ! -f "${built_binary}" ]]; then
die "Build completed but binary not found at: ${built_binary}"
fi
Expand Down
3 changes: 3 additions & 0 deletions amneziawg-web.sh
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ bootstrap_repo_if_needed() {
local root_seen
local -a bootstrap_roots=()
local -a tried_roots=()
if [[ -n "${AMNEZIAWG_BUILD_ROOT:-}" ]]; then
bootstrap_roots+=("${AMNEZIAWG_BUILD_ROOT}")
fi
if [[ -n "${TMPDIR:-}" ]]; then
bootstrap_roots+=("${TMPDIR}")
fi
Expand Down
6 changes: 6 additions & 0 deletions amneziawg-web/docs/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ for all options.
|---|---|---|
| Linux | Any modern kernel | x86_64 or aarch64 |
| Rust toolchain | 1.75+ | Install via [rustup](https://rustup.rs/) or use `--install-rust` |
| Build space | 2 GiB | Required only when compiling from source |
| AmneziaWG | Any release | `awg` binary must be at `/usr/bin/awg` |
| SQLite | 3.x | No separate install needed — embedded in binary via sqlx |
| Reverse proxy | nginx ≥ 1.18 or Caddy 2 | Required for TLS in production |
Expand All @@ -65,6 +66,11 @@ for all options.
> The installer can install Rust for you with `--install-rust`. If you use `--binary-src`
> to provide a pre-built binary, Rust is not required on the target host.

For source builds, the installer automatically moves Cargo artifacts away from
a small or noexec source filesystem and limits Cargo to one job on a one-vCPU
or low-memory host. Set `AMNEZIAWG_BUILD_ROOT` to an existing writable directory
on an executable filesystem if you need to select the build disk explicitly.

---

## 1. Build from source
Expand Down
12 changes: 11 additions & 1 deletion amneziawg-web/scripts/amneziawg-web-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ readonly AWG_INSTALL_SCRIPT_DEST="/usr/local/bin/amneziawg-install.sh"
readonly AWG_INSTALL_SCRIPT_MARKER_NAME="installed-awg-script.path"
readonly PRIVILEGED_HELPER_NAME="amneziawg-web-privileged"
readonly PRIVILEGED_HELPER_DEST="/usr/local/libexec/${PRIVILEGED_HELPER_NAME}"
readonly BUILD_MIN_FREE_KB="2097152"

# Default paths
readonly DEFAULT_BINARY_SRC="./target/release/amneziawg-web"
Expand All @@ -49,6 +50,9 @@ readonly DEFAULT_USERNAME="admin"
# Script location (for finding the service unit file relative to the repo)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# shellcheck source=../../scripts/amneziawg-cargo-build.sh
. "${SCRIPT_DIR}/../../scripts/amneziawg-cargo-build.sh"

# ── Colours ───────────────────────────────────────────────────────────────────

RED='\033[0;31m'
Expand Down Expand Up @@ -181,6 +185,7 @@ cleanup_staged_privilege_artifacts() {
report_retained_install_rollback_artifacts
fi

awg_cleanup_cargo_build
return "${exit_code}"
}

Expand Down Expand Up @@ -407,6 +412,10 @@ Expected the amneziawg-web Rust crate directory."

ensure_rust_toolchain

if ! awg_prepare_cargo_build "${SOURCE_DIR}" "amneziawg-web" "${BUILD_MIN_FREE_KB}"; then
die "No suitable build environment is available for amneziawg-web."
fi

info "Building in: ${SOURCE_DIR}"
info "Running: cargo build --release --locked"

Expand All @@ -415,7 +424,8 @@ Expected the amneziawg-web Rust crate directory."
Ensure build dependencies are installed (gcc, pkg-config, libssl-dev or equivalent)."
fi

local built_binary="${SOURCE_DIR}/target/release/amneziawg-web"
local built_binary
built_binary="$(awg_cargo_release_binary "amneziawg-web")"
if [[ ! -f "${built_binary}" ]]; then
die "Build completed but binary not found at: ${built_binary}"
fi
Expand Down
Loading