mirror of
https://github.com/ArchiveBox/ArchiveBox.git
synced 2026-09-12 19:50:57 +05:00
Make get.archivebox.io a uv install shortcut
This commit is contained in:
parent
96e129d3ad
commit
08c639c25d
11
README.md
11
README.md
@ -98,7 +98,7 @@ archivebox install
|
||||
# archivebox server 0.0.0.0:8000
|
||||
<br/>
|
||||
<br/>
|
||||
# Option D: Or use the optional auto setup script to install it
|
||||
# Option D: Or use the uv install shortcut for Option C
|
||||
curl -fsSL 'https://get.archivebox.io' | bash
|
||||
</code></pre>
|
||||
<br/>
|
||||
@ -208,18 +208,17 @@ See <a href="#%EF%B8%8F-cli-usage">below</a> for more usage examples using the C
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b><img src="https://user-images.githubusercontent.com/511499/117456282-08665e80-af16-11eb-91a1-8102eff54091.png" alt="curl sh automatic setup script" height="28px" align="top"/> <code>bash</code> auto-setup script</b> (macOS/Linux)</summary>
|
||||
<summary><b><img src="https://user-images.githubusercontent.com/511499/117456282-08665e80-af16-11eb-91a1-8102eff54091.png" alt="curl sh uv install shortcut" height="28px" align="top"/> <code>bash</code> uv install shortcut</b> (macOS/Linux/BSD)</summary>
|
||||
<br/>
|
||||
<ol>
|
||||
<li>Install <a href="https://docs.docker.com/get-docker/">Docker</a> on your system (optional, highly recommended but not required).</li>
|
||||
<li>Run the automatic setup script.
|
||||
<li>Run the shortcut for the <code>uv</code> install method. It installs <code>uv</code> first when needed.
|
||||
<pre lang="bash"><code style="white-space: pre-line">curl -fsSL 'https://get.archivebox.io' | bash</code></pre>
|
||||
<i>For more info, see <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Install#option-b-automatic-setup-script">Install: Bare Metal</a> in the Wiki. ➡️</i>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
See <a href="#%EF%B8%8F-cli-usage">below</a> for more usage examples using the CLI, Web UI, or filesystem/SQL/Python to manage your archive.<br/>
|
||||
See <a href="https://github.com/ArchiveBox/ArchiveBox/blob/dev/bin/setup.sh"><code>setup.sh</code></a> for the source code of the auto-install script.<br/>
|
||||
See <a href="https://github.com/ArchiveBox/ArchiveBox/blob/dev/bin/setup.sh"><code>setup.sh</code></a> for the source code of the <code>uv</code> install shortcut.<br/>
|
||||
See <a href="https://docs.sweeting.me/s/against-curl-sh">"Against curl | sh as an install method"</a> blog post for my thoughts on the shortcomings of this install method.
|
||||
<br/><br/>
|
||||
</details>
|
||||
@ -340,7 +339,7 @@ See <a href="#%EF%B8%8F-cli-usage">below</a> for more usage examples using the C
|
||||
|
||||
<ul>
|
||||
<li>Arch: <a href="https://aur.archlinux.org/packages/archivebox/"><code>yay -S archivebox</code></a> (contributed by <a href="https://github.com/imlonghao"><code>@imlonghao</code></a>, maintained by <a href="https://github.com/jasongodev"><code>@jasongodev</code></a>)</li>
|
||||
<li>FreeBSD: <a href="https://github.com/ArchiveBox/ArchiveBox#%EF%B8%8F-easy-setup"><code>curl -fsSL 'https://get.archivebox.io' | bash</code></a> (uses <code>pkg</code> + <code>uv</code> under-the-hood)</li>
|
||||
<li>FreeBSD: <a href="https://github.com/ArchiveBox/ArchiveBox#%EF%B8%8F-easy-setup"><code>curl -fsSL 'https://get.archivebox.io' | bash</code></a> (uses <code>uv</code>)</li>
|
||||
<li>Nix: <a href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/misc/archivebox/default.nix"><code>nix-env --install archivebox</code></a> (contributed by <a href="https://github.com/siraben"><code>@siraben</code></a>)</li>
|
||||
<li>Guix: <a href="https://packages.guix.gnu.org/packages/archivebox/"><code>guix install archivebox</code></a> (contributed by <a href="https://github.com/rakino"><code>@rakino</code></a>)</li>
|
||||
<li>More: <a href="https://github.com/ArchiveBox/ArchiveBox/issues/new"><i>contribute another distribution...!</i></a></li>
|
||||
|
||||
@ -1,199 +1,34 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SETUP_SCRIPT = Path(__file__).parents[2] / "bin" / "setup.sh"
|
||||
|
||||
|
||||
def test_setup_script_creates_archivebox_user_instead_of_rejecting_root():
|
||||
def test_setup_script_is_a_uv_install_shortcut():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
install_flow = script.partition("cat <<EOF")[0]
|
||||
|
||||
assert "You cannot run this script as root" not in script
|
||||
assert "useradd --system --create-home" in script
|
||||
assert 'ARCHIVEBOX_SYSTEM_USER="archivebox"' in script
|
||||
assert "${BOOTSTRAP_UV_BINARY#/var/root/}" in script
|
||||
assert "mkdir -p /usr/local/bin" in script
|
||||
|
||||
|
||||
def test_setup_script_never_recursively_chowns_collection_data():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
|
||||
assert 'chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" "$ARCHIVEBOX_HOME_DIR" "$ARCHIVEBOX_DATA_DIR"' in script
|
||||
assert "chown -R" not in script
|
||||
|
||||
|
||||
def test_setup_script_gives_archivebox_user_ownership_of_runtime_parent_dirs():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
|
||||
assert 'for path in "$HOME/.local" "$HOME/.local/share" "$HOME/.cache" "$HOME/.cache/archivebox" "$HOME/.config"; do' in script
|
||||
assert 'chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" "$path"' in script
|
||||
assert '"$HOME/.config/uv"' in script
|
||||
assert 'runuser -u "$ARCHIVEBOX_SYSTEM_USER"' in script
|
||||
assert '(cd "$HOME" && runuser' in script
|
||||
assert 'run_as_archivebox_user "$BOOTSTRAP_UV_BINARY" tool run' in script
|
||||
assert 'run_as_archivebox_user "$UV_BINARY" --no-config tool install' in script
|
||||
|
||||
|
||||
def test_setup_script_bootstraps_locked_abxpkg_version():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
lock = tomllib.loads((SETUP_SCRIPT.parents[1] / "uv.lock").read_text())
|
||||
locked_abxpkg_version = next(package["version"] for package in lock["package"] if package["name"] == "abxpkg")
|
||||
prepare_function = script.partition("prepare_abxpkg_environment() {")[2].partition("\n}")[0]
|
||||
install_function = script.partition("install_archivebox_with_uv() {")[2].partition("\n}")[0]
|
||||
|
||||
assert f'ABXPKG_PACKAGE="${{ABXPKG_PACKAGE:-abxpkg=={locked_abxpkg_version}}}"' in script
|
||||
assert 'ARCHIVEBOX_PYTHON="${ARCHIVEBOX_PYTHON:-3.13}"' in script
|
||||
assert 'ARCHIVEBOX_PACKAGE="${ARCHIVEBOX_PACKAGE:-archivebox>=0.9.0rc0,<0.10}"' in script
|
||||
assert '--prerelease explicit --upgrade "$ARCHIVEBOX_PACKAGE"' in install_function
|
||||
assert "fix_root_install_ownership" in prepare_function
|
||||
assert "resolve_setup_binary git env,brew,apt true" not in install_function
|
||||
assert '"$UV_BINARY" tool install --python "$ARCHIVEBOX_PYTHON" --prerelease explicit --upgrade "$ARCHIVEBOX_PACKAGE"' in install_flow
|
||||
assert "https://astral.sh/uv/install.sh" in script
|
||||
assert "archivebox init" not in install_flow
|
||||
assert "archivebox install" not in install_flow
|
||||
|
||||
|
||||
def test_setup_script_preserves_collection_and_compose_ownership_boundaries():
|
||||
def test_setup_script_does_not_select_a_system_installer_or_runtime():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
|
||||
assert "data|docker-compose.yml|compose.yml|compose.yaml|.env|Caddyfile)" in script
|
||||
assert 'mv -n "$path" "$ARCHIVEBOX_DATA_DIR/"' in script
|
||||
assert "if [ ! -f docker-compose.yml ]; then" in script
|
||||
assert 'chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" docker-compose.yml' in script
|
||||
assert 'mv -i "$HOME"/archivebox/*' not in script
|
||||
assert "docker" not in script.lower()
|
||||
assert "debian-archivebox" not in script
|
||||
assert "apt-get" not in script
|
||||
assert "launchpad" not in script
|
||||
assert "archivebox server" not in script
|
||||
assert "useradd" not in script
|
||||
|
||||
|
||||
def test_setup_script_prints_root_safe_runtime_commands():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
def test_setup_script_has_valid_bash_syntax():
|
||||
result = subprocess.run(["bash", "-n", SETUP_SCRIPT], capture_output=True, text=True, timeout=10)
|
||||
|
||||
assert 'echo " cd $ARCHIVEBOX_DATA_DIR' in script
|
||||
assert 'FOLLOWUP_SUDO="sudo "' in script
|
||||
assert "${FOLLOWUP_SUDO}docker compose exec archivebox archivebox add" in script
|
||||
assert "${FOLLOWUP_SUDO}archivebox add" in script
|
||||
assert "at ~/archivebox/data" not in script
|
||||
assert "Server started on http://0.0.0.0" not in script
|
||||
assert "server --daemonize 0.0.0.0:8000" in script
|
||||
assert 'nohup "$ARCHIVEBOX_BINARY" server' not in script
|
||||
assert "pkill -f 'archivebox server'" in script
|
||||
assert "pkill -f archivebox " not in script
|
||||
assert '"$DOCKER_BINARY" rm -f archivebox' in script
|
||||
assert "--connect-timeout 1 --max-time 2" in script
|
||||
assert "manage createsuperuser" not in script
|
||||
assert "Open http://localhost:8000/admin/ to create the first admin and finish web setup." in script
|
||||
assert '"$OPEN_BINARY" "http://admin.archivebox.localhost:8000/admin/"' in script
|
||||
|
||||
|
||||
def test_setup_script_pulls_docker_image_once_and_reports_unavailable_docker_accurately():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
install_flow = script.partition("prepare_abxpkg_environment")[2]
|
||||
|
||||
assert install_flow.count("docker_pull_archivebox") == 1
|
||||
assert "Docker wasn't found" not in install_flow
|
||||
assert "not installed, not running, or not accessible to this user" in install_flow
|
||||
|
||||
|
||||
def test_setup_script_does_not_fail_when_clear_cannot_use_terminal():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
|
||||
assert "if [ -t 1 ]; then\n clear || true\nfi" in script
|
||||
|
||||
|
||||
def test_setup_script_keeps_optional_binary_probes_quiet():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
|
||||
assert "resolve_setup_binary open env false 2>/dev/null" in script
|
||||
assert "resolve_setup_binary docker env false 2>/dev/null" in script
|
||||
assert 'if [ -n "$OPEN_BINARY" ] && [ -t 1 ]; then' in script
|
||||
|
||||
|
||||
def test_setup_script_selects_collection_library_before_installing_dependencies():
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
native_install = script.partition(': | "$ARCHIVEBOX_BINARY" init')[2]
|
||||
|
||||
select_library = "select_archivebox_lib_dir"
|
||||
install_dependencies = '"$ARCHIVEBOX_BINARY" install'
|
||||
|
||||
assert select_library in native_install
|
||||
assert native_install.index(select_library) < native_install.index(install_dependencies)
|
||||
|
||||
|
||||
def test_setup_script_preserves_existing_collection_library(tmp_path):
|
||||
archivebox_binary = shutil.which("archivebox")
|
||||
assert archivebox_binary
|
||||
|
||||
data_dir = tmp_path / "data"
|
||||
data_dir.mkdir()
|
||||
bootstrap_lib = tmp_path / "bootstrap-lib"
|
||||
configured_lib = tmp_path / "configured-lib"
|
||||
command_env = {**os.environ, "HOME": str(tmp_path), "ABXPKG_LIB_DIR": str(bootstrap_lib), "TERM": "dumb"}
|
||||
|
||||
init_result = subprocess.run(
|
||||
[archivebox_binary, "init"],
|
||||
cwd=data_dir,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=command_env,
|
||||
timeout=60,
|
||||
)
|
||||
assert init_result.returncode == 0, init_result.stderr or init_result.stdout
|
||||
|
||||
config_result = subprocess.run(
|
||||
[archivebox_binary, "config", "--set", f"ABXPKG_LIB_DIR={configured_lib}"],
|
||||
cwd=data_dir,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=command_env,
|
||||
timeout=60,
|
||||
)
|
||||
assert config_result.returncode == 0, config_result.stderr or config_result.stdout
|
||||
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
function_body = script.partition("select_archivebox_lib_dir() {")[2].partition("\n}")[0]
|
||||
harness = tmp_path / "select-library.sh"
|
||||
harness.write_text(f"select_archivebox_lib_dir() {{{function_body}\n}}\n")
|
||||
|
||||
select_result = subprocess.run(
|
||||
[
|
||||
"bash",
|
||||
"-c",
|
||||
'source "$1"; ARCHIVEBOX_BINARY="$2"; select_archivebox_lib_dir; printf "%s" "$ABXPKG_LIB_DIR"',
|
||||
"bash",
|
||||
str(harness),
|
||||
archivebox_binary,
|
||||
],
|
||||
cwd=data_dir,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=command_env,
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
assert select_result.returncode == 0, select_result.stderr or select_result.stdout
|
||||
assert select_result.stdout == str(configured_lib)
|
||||
|
||||
|
||||
def test_setup_script_moves_legacy_collection_without_moving_compose(tmp_path):
|
||||
script = SETUP_SCRIPT.read_text()
|
||||
function_prefix = script.partition("\ndocker_pull_archivebox() {")[0]
|
||||
harness = tmp_path / "setup-functions.sh"
|
||||
harness.write_text(function_prefix)
|
||||
|
||||
archivebox_home = tmp_path / "archivebox"
|
||||
data_dir = archivebox_home / "data"
|
||||
data_dir.mkdir(parents=True)
|
||||
(data_dir / "existing.txt").write_text("keep")
|
||||
(archivebox_home / "index.sqlite3").write_text("legacy-db")
|
||||
(archivebox_home / ".archivebox_id").write_text("legacy-id")
|
||||
(archivebox_home / "docker-compose.yml").write_text("services: {}")
|
||||
|
||||
result = subprocess.run(
|
||||
["bash", "-c", 'source "$1"; migrate_legacy_collection_dir', "bash", str(harness)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env={**os.environ, "HOME": str(tmp_path), "TERM": "xterm"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert result.returncode == 0, result.stderr or result.stdout
|
||||
assert (data_dir / "existing.txt").read_text() == "keep"
|
||||
assert (data_dir / "index.sqlite3").read_text() == "legacy-db"
|
||||
assert (data_dir / ".archivebox_id").read_text() == "legacy-id"
|
||||
assert (archivebox_home / "docker-compose.yml").read_text() == "services: {}"
|
||||
assert result.returncode == 0, result.stderr
|
||||
|
||||
@ -64,24 +64,3 @@ if next(package['version'] for package in locked['package'] if package['name'] =
|
||||
raise SystemExit('Updated ArchiveBox lock version does not match the requested version')
|
||||
print(version)
|
||||
PY
|
||||
|
||||
uv run --no-cache --no-project python - <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
import tomllib
|
||||
|
||||
packages = tomllib.loads(Path('uv.lock').read_text())['package']
|
||||
abxpkg_version = next(package['version'] for package in packages if package['name'] == 'abxpkg')
|
||||
setup_path = Path('bin/setup.sh')
|
||||
setup = setup_path.read_text()
|
||||
updated, count = re.subn(
|
||||
r'^(ABXPKG_PACKAGE="\$\{ABXPKG_PACKAGE:-abxpkg==)[^}"]+(\}")$',
|
||||
rf'\g<1>{abxpkg_version}\g<2>',
|
||||
setup,
|
||||
count=1,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
if count != 1:
|
||||
raise SystemExit('Failed to update ABXPKG_PACKAGE in bin/setup.sh')
|
||||
setup_path.write_text(updated)
|
||||
PY
|
||||
|
||||
516
bin/setup.sh
516
bin/setup.sh
@ -1,507 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# ArchiveBox Setup Script (Ubuntu/Debian/FreeBSD/macOS)
|
||||
# - Project Homepage: https://github.com/ArchiveBox/ArchiveBox
|
||||
# - Install Documentation: https://github.com/ArchiveBox/ArchiveBox/wiki/Install
|
||||
# Script Usage:
|
||||
# curl -fsSL 'https://raw.githubusercontent.com/ArchiveBox/ArchiveBox/dev/bin/setup.sh' | bash
|
||||
# (aka https://get.archivebox.io)
|
||||
# ArchiveBox uv install shortcut (macOS/Linux/BSD)
|
||||
#
|
||||
# Usage:
|
||||
# curl -fsSL 'https://get.archivebox.io' | bash
|
||||
|
||||
### Bash Environment Setup
|
||||
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
|
||||
# https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
|
||||
set -e
|
||||
set -u
|
||||
if (set -o pipefail) 2>/dev/null; then
|
||||
set -o pipefail
|
||||
fi
|
||||
if (set -o errtrace) 2>/dev/null; then
|
||||
set -o errtrace
|
||||
fi
|
||||
if [ -t 1 ]; then
|
||||
clear || true
|
||||
fi
|
||||
set -Eeuo pipefail
|
||||
|
||||
RUNNING_AS_ROOT="false"
|
||||
ARCHIVEBOX_SYSTEM_USER="archivebox"
|
||||
ARCHIVEBOX_SYSTEM_UID=""
|
||||
ARCHIVEBOX_SYSTEM_GID=""
|
||||
FOLLOWUP_SUDO=""
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
RUNNING_AS_ROOT="true"
|
||||
if ! id "$ARCHIVEBOX_SYSTEM_USER" >/dev/null 2>&1; then
|
||||
echo "[+] Creating the archivebox system user..."
|
||||
case "$(uname -s)" in
|
||||
Linux)
|
||||
useradd --system --create-home --home-dir /var/lib/archivebox --shell /bin/bash "$ARCHIVEBOX_SYSTEM_USER"
|
||||
;;
|
||||
FreeBSD)
|
||||
pw useradd "$ARCHIVEBOX_SYSTEM_USER" -m -d /var/db/archivebox -s /bin/sh
|
||||
;;
|
||||
Darwin)
|
||||
archivebox_uid=499
|
||||
while dscl . -search /Users UniqueID "$archivebox_uid" 2>/dev/null | grep -q .; do
|
||||
archivebox_uid=$((archivebox_uid - 1))
|
||||
done
|
||||
dscl . -create "/Users/$ARCHIVEBOX_SYSTEM_USER"
|
||||
dscl . -create "/Users/$ARCHIVEBOX_SYSTEM_USER" RealName ArchiveBox
|
||||
dscl . -create "/Users/$ARCHIVEBOX_SYSTEM_USER" UserShell /bin/bash
|
||||
dscl . -create "/Users/$ARCHIVEBOX_SYSTEM_USER" UniqueID "$archivebox_uid"
|
||||
dscl . -create "/Users/$ARCHIVEBOX_SYSTEM_USER" PrimaryGroupID 20
|
||||
dscl . -create "/Users/$ARCHIVEBOX_SYSTEM_USER" NFSHomeDirectory "/Users/$ARCHIVEBOX_SYSTEM_USER"
|
||||
mkdir -p "/Users/$ARCHIVEBOX_SYSTEM_USER"
|
||||
chown "$archivebox_uid:20" "/Users/$ARCHIVEBOX_SYSTEM_USER"
|
||||
;;
|
||||
*)
|
||||
echo "[X] Cannot create the archivebox system user on $(uname -s)."
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
ARCHIVEBOX_SYSTEM_UID="$(id -u "$ARCHIVEBOX_SYSTEM_USER")"
|
||||
ARCHIVEBOX_SYSTEM_GID="$(id -g "$ARCHIVEBOX_SYSTEM_USER")"
|
||||
if command -v getent >/dev/null 2>&1; then
|
||||
HOME="$(getent passwd "$ARCHIVEBOX_SYSTEM_USER" | cut -d: -f6)"
|
||||
elif [ "$(uname -s)" = "FreeBSD" ]; then
|
||||
HOME="$(pw usershow "$ARCHIVEBOX_SYSTEM_USER" | cut -d: -f9)"
|
||||
else
|
||||
HOME="$(dscl . -read "/Users/$ARCHIVEBOX_SYSTEM_USER" NFSHomeDirectory | awk '{print $2}')"
|
||||
fi
|
||||
export HOME
|
||||
fi
|
||||
|
||||
if [ "$RUNNING_AS_ROOT" = "true" ] && [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != "root" ]; then
|
||||
FOLLOWUP_SUDO="sudo "
|
||||
fi
|
||||
|
||||
ARCHIVEBOX_BRANCH="${ARCHIVEBOX_BRANCH:-dev}"
|
||||
ARCHIVEBOX_IMAGE="${ARCHIVEBOX_IMAGE:-archivebox/archivebox:dev}"
|
||||
ARCHIVEBOX_PYTHON="${ARCHIVEBOX_PYTHON:-3.13}"
|
||||
ARCHIVEBOX_PACKAGE="${ARCHIVEBOX_PACKAGE:-archivebox>=0.9.0rc0,<0.10}"
|
||||
ARCHIVEBOX_PLATFORM="${ARCHIVEBOX_PLATFORM:-}"
|
||||
ARCHIVEBOX_COMPOSE_URL="${ARCHIVEBOX_COMPOSE_URL:-https://raw.githubusercontent.com/ArchiveBox/ArchiveBox/${ARCHIVEBOX_BRANCH}/docker-compose.yml}"
|
||||
ABXPKG_PACKAGE="${ABXPKG_PACKAGE:-abxpkg==1.12.109}"
|
||||
ABXPKG_LIB_DIR="${ABXPKG_LIB_DIR:-$HOME/.cache/archivebox/setup-abxpkg}"
|
||||
ARCHIVEBOX_HOME_DIR="$HOME/archivebox"
|
||||
ARCHIVEBOX_DATA_DIR="$ARCHIVEBOX_HOME_DIR/data"
|
||||
BOOTSTRAP_UV_BINARY=""
|
||||
UV_BINARY=""
|
||||
DOCKER_BINARY=""
|
||||
CURL_BINARY=""
|
||||
OPEN_BINARY=""
|
||||
ARCHIVEBOX_BINARY=""
|
||||
DOCKER_PLATFORM_ARGS=""
|
||||
if [ -n "$ARCHIVEBOX_PLATFORM" ]; then
|
||||
DOCKER_PLATFORM_ARGS="--platform $ARCHIVEBOX_PLATFORM"
|
||||
fi
|
||||
DOCKER_RUN_TTY_ARG="-i"
|
||||
DOCKER_COMPOSE_RUN_TTY_ARG="-T"
|
||||
if [ -t 0 ]; then
|
||||
DOCKER_RUN_TTY_ARG="-it"
|
||||
DOCKER_COMPOSE_RUN_TTY_ARG=""
|
||||
fi
|
||||
|
||||
fix_root_install_ownership() {
|
||||
if [ "$RUNNING_AS_ROOT" != "true" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Keep shared runtime parents writable after ArchiveBox drops privileges.
|
||||
for path in "$HOME/.local" "$HOME/.local/share" "$HOME/.cache" "$HOME/.cache/archivebox" "$HOME/.config"; do
|
||||
if [ -e "$path" ]; then
|
||||
chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" "$path"
|
||||
fi
|
||||
done
|
||||
|
||||
# Only hand off bounded runtime roots. Provider libraries can be very large,
|
||||
# and their existing contents only need to remain readable/executable.
|
||||
for path in "$HOME/.local/bin" "$HOME/.local/share/uv" "$HOME/.cache/uv" "$HOME/.config/uv" "$ABXPKG_LIB_DIR" "$ABXPKG_LIB_DIR/env" "$ABXPKG_LIB_DIR/env/bin"; do
|
||||
if [ -e "$path" ]; then
|
||||
chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" "$path"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
run_as_archivebox_user() {
|
||||
if [ "$RUNNING_AS_ROOT" != "true" ]; then
|
||||
"$@"
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v runuser >/dev/null 2>&1; then
|
||||
(cd "$HOME" && runuser -u "$ARCHIVEBOX_SYSTEM_USER" -- env HOME="$HOME" PATH="$PATH" ABXPKG_LIB_DIR="$ABXPKG_LIB_DIR" "$@")
|
||||
else
|
||||
(cd "$HOME" && sudo -u "$ARCHIVEBOX_SYSTEM_USER" env HOME="$HOME" PATH="$PATH" ABXPKG_LIB_DIR="$ABXPKG_LIB_DIR" "$@")
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_archivebox_data_dir() {
|
||||
mkdir -p "$ARCHIVEBOX_DATA_DIR"
|
||||
if [ "$RUNNING_AS_ROOT" = "true" ]; then
|
||||
chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" "$ARCHIVEBOX_HOME_DIR" "$ARCHIVEBOX_DATA_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
migrate_legacy_collection_dir() {
|
||||
if [ ! -f "$ARCHIVEBOX_HOME_DIR/index.sqlite3" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
for path in "$ARCHIVEBOX_HOME_DIR"/* "$ARCHIVEBOX_HOME_DIR"/.[!.]* "$ARCHIVEBOX_HOME_DIR"/..?*; do
|
||||
if [ ! -e "$path" ] && [ ! -L "$path" ]; then
|
||||
continue
|
||||
fi
|
||||
case "$(basename "$path")" in
|
||||
data|docker-compose.yml|compose.yml|compose.yaml|.env|Caddyfile)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
mv -n "$path" "$ARCHIVEBOX_DATA_DIR/"
|
||||
done
|
||||
}
|
||||
|
||||
docker_pull_archivebox() {
|
||||
if [ -n "$ARCHIVEBOX_PLATFORM" ]; then
|
||||
"$DOCKER_BINARY" pull --platform "$ARCHIVEBOX_PLATFORM" "$ARCHIVEBOX_IMAGE"
|
||||
else
|
||||
"$DOCKER_BINARY" pull "$ARCHIVEBOX_IMAGE"
|
||||
fi
|
||||
}
|
||||
|
||||
docker_run_archivebox() {
|
||||
if [ -n "$ARCHIVEBOX_PLATFORM" ]; then
|
||||
"$DOCKER_BINARY" run --platform "$ARCHIVEBOX_PLATFORM" "$DOCKER_RUN_TTY_ARG" -v "$PWD":/data --rm "$ARCHIVEBOX_IMAGE" "$@"
|
||||
else
|
||||
"$DOCKER_BINARY" run "$DOCKER_RUN_TTY_ARG" -v "$PWD":/data --rm "$ARCHIVEBOX_IMAGE" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
docker_run_archivebox_init() {
|
||||
docker_run_archivebox init
|
||||
}
|
||||
|
||||
docker_run_archivebox_install() {
|
||||
docker_run_archivebox install
|
||||
}
|
||||
|
||||
docker_run_archivebox_server() {
|
||||
if [ -n "$ARCHIVEBOX_PLATFORM" ]; then
|
||||
"$DOCKER_BINARY" run --platform "$ARCHIVEBOX_PLATFORM" -v "$PWD":/data -d -p 8000:8000 --name=archivebox "$ARCHIVEBOX_IMAGE"
|
||||
else
|
||||
"$DOCKER_BINARY" run -v "$PWD":/data -d -p 8000:8000 --name=archivebox "$ARCHIVEBOX_IMAGE"
|
||||
fi
|
||||
}
|
||||
|
||||
docker_compose_run_archivebox() {
|
||||
if [ -n "$DOCKER_COMPOSE_RUN_TTY_ARG" ]; then
|
||||
"$DOCKER_BINARY" compose run "$DOCKER_COMPOSE_RUN_TTY_ARG" --rm archivebox "$@"
|
||||
else
|
||||
"$DOCKER_BINARY" compose run --rm archivebox "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
wait_for_archivebox() {
|
||||
url="http://127.0.0.1:8000/health/"
|
||||
host_header="admin.archivebox.localhost:8000"
|
||||
attempts=60
|
||||
attempt=1
|
||||
|
||||
while [ "$attempt" -le "$attempts" ]; do
|
||||
if "$CURL_BINARY" -fsS --connect-timeout 1 --max-time 2 -H "Host: ${host_header}" "$url" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
echo "[!] Server process started, but health check did not become ready at $url after ${attempts}s."
|
||||
echo " Inspect $ARCHIVEBOX_DATA_DIR/logs/ or run 'docker compose logs' to diagnose startup."
|
||||
return 1
|
||||
}
|
||||
|
||||
open_archivebox() {
|
||||
if [ -n "$OPEN_BINARY" ] && [ -t 1 ]; then
|
||||
"$OPEN_BINARY" "http://admin.archivebox.localhost:8000/admin/" || true
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_uv() {
|
||||
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
|
||||
|
||||
if command -v uv > /dev/null 2>&1; then
|
||||
BOOTSTRAP_UV_BINARY="$(command -v uv)"
|
||||
if [ "$RUNNING_AS_ROOT" = "true" ] && { [ "${BOOTSTRAP_UV_BINARY#/root/}" != "$BOOTSTRAP_UV_BINARY" ] || [ "${BOOTSTRAP_UV_BINARY#/var/root/}" != "$BOOTSTRAP_UV_BINARY" ]; }; then
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
install -m 0755 "$BOOTSTRAP_UV_BINARY" "$HOME/.local/bin/uv"
|
||||
if command -v uvx >/dev/null 2>&1; then
|
||||
install -m 0755 "$(command -v uvx)" "$HOME/.local/bin/uvx"
|
||||
fi
|
||||
fix_root_install_ownership
|
||||
BOOTSTRAP_UV_BINARY="$HOME/.local/bin/uv"
|
||||
fi
|
||||
if [ "$RUNNING_AS_ROOT" = "true" ] && [ "${BOOTSTRAP_UV_BINARY#"$HOME"/}" != "$BOOTSTRAP_UV_BINARY" ]; then
|
||||
chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" "$BOOTSTRAP_UV_BINARY"
|
||||
if [ -e "$HOME/.local/bin/uvx" ]; then
|
||||
chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" "$HOME/.local/bin/uvx"
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
export PATH="${XDG_BIN_HOME:-$HOME/.local/bin}:$HOME/.cargo/bin:$PATH"
|
||||
|
||||
UV_BINARY="$(command -v uv || true)"
|
||||
if [ -z "$UV_BINARY" ]; then
|
||||
echo "[+] Installing uv..."
|
||||
if command -v curl > /dev/null 2>&1; then
|
||||
if [ "$RUNNING_AS_ROOT" = "true" ]; then
|
||||
curl -LsSf https://astral.sh/uv/install.sh | run_as_archivebox_user env UV_NO_MODIFY_PATH=1 sh
|
||||
else
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
fi
|
||||
elif command -v wget > /dev/null 2>&1; then
|
||||
wget -qO- https://astral.sh/uv/install.sh | run_as_archivebox_user sh
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- https://astral.sh/uv/install.sh | sh
|
||||
else
|
||||
echo "[X] curl or wget is required to install uv."
|
||||
echo "[X] curl or wget is required to install uv." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
|
||||
if ! command -v uv > /dev/null 2>&1; then
|
||||
echo "[X] uv was installed, but the uv command was not found in PATH."
|
||||
echo " Add ~/.local/bin to PATH, then run this script again."
|
||||
exit 1
|
||||
fi
|
||||
BOOTSTRAP_UV_BINARY="$(command -v uv)"
|
||||
fix_root_install_ownership
|
||||
}
|
||||
|
||||
resolve_setup_binary() {
|
||||
local binary_name="$1"
|
||||
local binproviders="$2"
|
||||
local install_binary="$3"
|
||||
local resolved_binary
|
||||
local -a abxpkg_args=(
|
||||
env
|
||||
--json
|
||||
"--lib=$ABXPKG_LIB_DIR"
|
||||
"--binproviders=$binproviders"
|
||||
)
|
||||
if [ "$install_binary" = "true" ]; then
|
||||
abxpkg_args+=(--install)
|
||||
fi
|
||||
abxpkg_args+=("$binary_name")
|
||||
|
||||
run_as_archivebox_user "$BOOTSTRAP_UV_BINARY" tool run --from "$ABXPKG_PACKAGE" abxpkg "${abxpkg_args[@]}" >/dev/null
|
||||
|
||||
resolved_binary="$ABXPKG_LIB_DIR/env/bin/$binary_name"
|
||||
test -L "$resolved_binary"
|
||||
test -x "$resolved_binary"
|
||||
}
|
||||
|
||||
prepare_abxpkg_environment() {
|
||||
ensure_uv
|
||||
mkdir -p "$ABXPKG_LIB_DIR/env/bin"
|
||||
fix_root_install_ownership
|
||||
export ABXPKG_LIB_DIR
|
||||
export PATH="$ABXPKG_LIB_DIR/env/bin:$PATH"
|
||||
|
||||
resolve_setup_binary uv env false
|
||||
UV_BINARY="$ABXPKG_LIB_DIR/env/bin/uv"
|
||||
BOOTSTRAP_UV_BINARY="$UV_BINARY"
|
||||
|
||||
if resolve_setup_binary open env false 2>/dev/null; then
|
||||
OPEN_BINARY="$ABXPKG_LIB_DIR/env/bin/open"
|
||||
fi
|
||||
fix_root_install_ownership
|
||||
}
|
||||
|
||||
resolve_setup_curl() {
|
||||
resolve_setup_binary curl env,brew,apt true
|
||||
CURL_BINARY="$ABXPKG_LIB_DIR/env/bin/curl"
|
||||
}
|
||||
|
||||
install_archivebox_with_uv() {
|
||||
echo
|
||||
echo "[+] Installing ArchiveBox python tool using uv from $ARCHIVEBOX_PACKAGE..."
|
||||
run_as_archivebox_user "$UV_BINARY" --no-config tool install --python "$ARCHIVEBOX_PYTHON" --prerelease explicit --upgrade "$ARCHIVEBOX_PACKAGE"
|
||||
|
||||
uv_tool_bin_dir="$(run_as_archivebox_user "$UV_BINARY" --no-config tool dir --bin)"
|
||||
ARCHIVEBOX_BINARY="$uv_tool_bin_dir/archivebox"
|
||||
test -x "$ARCHIVEBOX_BINARY"
|
||||
if [ "$RUNNING_AS_ROOT" != "true" ]; then
|
||||
"$UV_BINARY" --no-config tool update-shell || true
|
||||
fi
|
||||
fix_root_install_ownership
|
||||
if [ "$RUNNING_AS_ROOT" = "true" ]; then
|
||||
mkdir -p /usr/local/bin
|
||||
ln -sf "$ARCHIVEBOX_BINARY" /usr/local/bin/archivebox
|
||||
ARCHIVEBOX_BINARY="/usr/local/bin/archivebox"
|
||||
fi
|
||||
}
|
||||
|
||||
select_archivebox_lib_dir() {
|
||||
local configured_lib_dir
|
||||
configured_lib_dir="$(
|
||||
COLUMNS=10000 env -u ABXPKG_LIB_DIR "$ARCHIVEBOX_BINARY" config --get ABXPKG_LIB_DIR \
|
||||
| awk '
|
||||
!found && /^[[:space:]]*ABXPKG_LIB_DIR[[:space:]]*=/ {
|
||||
value = $0
|
||||
sub(/^[^=]*=[[:space:]]*/, "", value)
|
||||
sub(/^"/, "", value)
|
||||
sub(/"[[:space:]]*$/, "", value)
|
||||
print value
|
||||
found = 1
|
||||
}
|
||||
'
|
||||
)"
|
||||
if [ -z "$configured_lib_dir" ]; then
|
||||
echo "[X] Could not resolve the ArchiveBox dependency library directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ABXPKG_LIB_DIR="$configured_lib_dir"
|
||||
export ABXPKG_LIB_DIR
|
||||
export PATH="$ABXPKG_LIB_DIR/env/bin:$PATH"
|
||||
fix_root_install_ownership
|
||||
}
|
||||
|
||||
prepare_abxpkg_environment
|
||||
if resolve_setup_binary docker env false 2>/dev/null; then
|
||||
DOCKER_BINARY="$ABXPKG_LIB_DIR/env/bin/docker"
|
||||
hash -r
|
||||
UV_BINARY="$(command -v uv || true)"
|
||||
fi
|
||||
|
||||
DOCKER_IMAGE_READY="false"
|
||||
if [ -n "$DOCKER_BINARY" ] && docker_pull_archivebox; then
|
||||
DOCKER_IMAGE_READY="true"
|
||||
if [ -z "$UV_BINARY" ]; then
|
||||
echo "[X] uv was installed but is not available on PATH." >&2
|
||||
echo " See https://docs.astral.sh/uv/getting-started/installation/" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$DOCKER_IMAGE_READY" = "true" ] && "$DOCKER_BINARY" compose version > /dev/null; then
|
||||
resolve_setup_curl
|
||||
echo "[+] Initializing an ArchiveBox data folder at $ARCHIVEBOX_DATA_DIR using Docker Compose..."
|
||||
ensure_archivebox_data_dir || exit 1
|
||||
cd "$ARCHIVEBOX_HOME_DIR"
|
||||
migrate_legacy_collection_dir
|
||||
if [ ! -f docker-compose.yml ]; then
|
||||
compose_download="$(mktemp "$ARCHIVEBOX_HOME_DIR/.docker-compose.yml.XXXXXX")"
|
||||
if ! "$CURL_BINARY" -fsSL "$ARCHIVEBOX_COMPOSE_URL" -o "$compose_download"; then
|
||||
rm -f "$compose_download"
|
||||
exit 1
|
||||
fi
|
||||
mv "$compose_download" docker-compose.yml
|
||||
if [ "$RUNNING_AS_ROOT" = "true" ]; then
|
||||
chown "$ARCHIVEBOX_SYSTEM_UID:$ARCHIVEBOX_SYSTEM_GID" docker-compose.yml
|
||||
fi
|
||||
fi
|
||||
export ARCHIVEBOX_IMAGE ARCHIVEBOX_PLATFORM
|
||||
docker_compose_run_archivebox init
|
||||
docker_compose_run_archivebox install
|
||||
echo
|
||||
echo "[+] Starting ArchiveBox server using: docker compose up -d..."
|
||||
"$DOCKER_BINARY" compose up -d
|
||||
wait_for_archivebox
|
||||
open_archivebox
|
||||
echo
|
||||
echo "[√] Server started on http://127.0.0.1:8000 and data directory initialized in $ARCHIVEBOX_DATA_DIR. Usage:"
|
||||
echo " cd $ARCHIVEBOX_HOME_DIR"
|
||||
echo " ${FOLLOWUP_SUDO}docker compose ps"
|
||||
echo " ${FOLLOWUP_SUDO}docker compose down"
|
||||
echo " ${FOLLOWUP_SUDO}env ARCHIVEBOX_IMAGE=$ARCHIVEBOX_IMAGE docker compose pull"
|
||||
echo " ${FOLLOWUP_SUDO}docker compose up"
|
||||
echo " Open http://localhost:8000/admin/ to create the first admin and finish web setup."
|
||||
echo " (When running remotely, replace localhost with this server's IP address or hostname.)"
|
||||
echo " ${FOLLOWUP_SUDO}docker compose exec archivebox archivebox add 'https://example.com'"
|
||||
echo " ${FOLLOWUP_SUDO}docker compose exec archivebox archivebox list"
|
||||
echo " ${FOLLOWUP_SUDO}docker compose exec archivebox archivebox help"
|
||||
exit 0
|
||||
elif [ "$DOCKER_IMAGE_READY" = "true" ]; then
|
||||
resolve_setup_curl
|
||||
echo "[+] Initializing an ArchiveBox data folder at $ARCHIVEBOX_DATA_DIR using Docker..."
|
||||
ensure_archivebox_data_dir || exit 1
|
||||
cd "$ARCHIVEBOX_HOME_DIR"
|
||||
migrate_legacy_collection_dir
|
||||
cd ./data
|
||||
docker_run_archivebox_init
|
||||
docker_run_archivebox_install
|
||||
echo
|
||||
echo "[+] Starting ArchiveBox server using: docker run -d $ARCHIVEBOX_IMAGE..."
|
||||
"$DOCKER_BINARY" rm -f archivebox >/dev/null 2>&1 || true
|
||||
docker_run_archivebox_server
|
||||
wait_for_archivebox
|
||||
open_archivebox
|
||||
echo
|
||||
echo "[√] Server started on http://127.0.0.1:8000 and data directory initialized in $ARCHIVEBOX_DATA_DIR. Usage:"
|
||||
echo " cd $ARCHIVEBOX_DATA_DIR"
|
||||
echo " ${FOLLOWUP_SUDO}docker ps --filter name=archivebox"
|
||||
echo " ${FOLLOWUP_SUDO}docker rm -f archivebox"
|
||||
echo " ${FOLLOWUP_SUDO}docker pull $ARCHIVEBOX_IMAGE"
|
||||
echo " ${FOLLOWUP_SUDO}docker run $DOCKER_PLATFORM_ARGS -v $PWD:/data -d -p 8000:8000 --name=archivebox $ARCHIVEBOX_IMAGE"
|
||||
echo " Open http://localhost:8000/admin/ to create the first admin and finish web setup."
|
||||
echo " (When running remotely, replace localhost with this server's IP address or hostname.)"
|
||||
echo " ${FOLLOWUP_SUDO}docker run $DOCKER_PLATFORM_ARGS -v $PWD:/data -it $ARCHIVEBOX_IMAGE add 'https://example.com'"
|
||||
echo " ${FOLLOWUP_SUDO}docker run $DOCKER_PLATFORM_ARGS -v $PWD:/data -it $ARCHIVEBOX_IMAGE list"
|
||||
echo " ${FOLLOWUP_SUDO}docker run $DOCKER_PLATFORM_ARGS -v $PWD:/data -it $ARCHIVEBOX_IMAGE help"
|
||||
exit 0
|
||||
fi
|
||||
echo "[+] Installing ArchiveBox with uv..."
|
||||
"$UV_BINARY" tool install --python "$ARCHIVEBOX_PYTHON" --prerelease explicit --upgrade "$ARCHIVEBOX_PACKAGE"
|
||||
|
||||
echo
|
||||
echo "[!] It's highly recommended to use ArchiveBox with Docker, but Docker is unavailable (not installed, not running, or not accessible to this user)."
|
||||
echo
|
||||
echo " ⚠️ If you want to use Docker, press [Ctrl-C] to cancel now. ⚠️"
|
||||
echo " Check 'docker info'. Start Docker Desktop on macOS, or fix Docker socket access and rerun as your normal Ubuntu user."
|
||||
echo " Rerunning with sudo intentionally creates a system-owned deployment under /var/lib/archivebox/archivebox instead of ~/archivebox."
|
||||
echo " Install Docker if needed: https://docs.docker.com/get-docker/"
|
||||
echo
|
||||
echo "Otherwise, install will continue with uv in 12s... (press [Ctrl+C] to cancel)"
|
||||
echo
|
||||
sleep 12 || exit 1
|
||||
echo "Proceeding with uv..."
|
||||
echo
|
||||
cat <<EOF
|
||||
|
||||
echo "[i] ArchiveBox Setup Script 📦"
|
||||
echo
|
||||
echo " This is a helper script which installs ArchiveBox and bootstraps its runtime dependencies."
|
||||
echo " You may be prompted for a sudo password in order to install the following:"
|
||||
echo
|
||||
echo " - uv / curl / ca-certificates (as needed to bootstrap ArchiveBox)"
|
||||
echo " - archivebox (installed by uv with Python $ARCHIVEBOX_PYTHON)"
|
||||
echo " - extractor/plugin dependencies (installed/discovered by archivebox install)"
|
||||
echo
|
||||
echo " If you'd rather install these manually as-needed, you can find detailed documentation here:"
|
||||
echo " https://github.com/ArchiveBox/ArchiveBox/wiki/Install"
|
||||
echo
|
||||
echo "Continuing in 12s... (press [Ctrl+C] to cancel)"
|
||||
echo
|
||||
sleep 12 || exit 1
|
||||
echo "Proceeding to install ArchiveBox..."
|
||||
echo
|
||||
[+] ArchiveBox is installed. Initialize a collection when you are ready:
|
||||
|
||||
echo
|
||||
mkdir -p ~/archivebox/data
|
||||
cd ~/archivebox/data
|
||||
archivebox init
|
||||
archivebox install
|
||||
|
||||
resolve_setup_curl
|
||||
install_archivebox_with_uv
|
||||
|
||||
echo
|
||||
echo "[+] Initializing ArchiveBox data folder at $ARCHIVEBOX_DATA_DIR..."
|
||||
ensure_archivebox_data_dir || exit 1
|
||||
cd "$ARCHIVEBOX_HOME_DIR"
|
||||
migrate_legacy_collection_dir
|
||||
cd ./data
|
||||
: | "$ARCHIVEBOX_BINARY" init # pipe in empty command to make sure stdin is closed
|
||||
select_archivebox_lib_dir
|
||||
"$ARCHIVEBOX_BINARY" install
|
||||
# init shows version output at the end too
|
||||
echo
|
||||
echo "[+] Starting ArchiveBox server using: archivebox server --daemonize..."
|
||||
"$ARCHIVEBOX_BINARY" server --daemonize 0.0.0.0:8000
|
||||
wait_for_archivebox
|
||||
open_archivebox
|
||||
echo
|
||||
echo "[√] Server started on http://127.0.0.1:8000 and data directory initialized in $ARCHIVEBOX_DATA_DIR. Usage:"
|
||||
echo " cd $ARCHIVEBOX_DATA_DIR # see your data dir"
|
||||
echo " ${FOLLOWUP_SUDO}archivebox server 0.0.0.0:8000 # start server process"
|
||||
echo " Open http://localhost:8000/admin/ to create the first admin and finish web setup."
|
||||
echo " (When running remotely, replace localhost with this server's IP address or hostname.)"
|
||||
echo " ps aux | grep archivebox # see server process pid"
|
||||
echo " ${FOLLOWUP_SUDO}pkill -f 'archivebox server' # stop the server"
|
||||
echo " curl -fsSL 'https://raw.githubusercontent.com/ArchiveBox/ArchiveBox/dev/bin/setup.sh' | ${FOLLOWUP_SUDO}bash # update versions"
|
||||
echo " ${FOLLOWUP_SUDO}archivebox add 'https://example.com'" # archive a new URL
|
||||
echo " ${FOLLOWUP_SUDO}archivebox list # see URLs archived"
|
||||
echo " ${FOLLOWUP_SUDO}archivebox help # see more help & examples"
|
||||
More install and usage options: https://github.com/ArchiveBox/ArchiveBox/wiki/Install
|
||||
EOF
|
||||
|
||||
@ -9,7 +9,7 @@ ArchiveBox is primarily distributed as a Python package installed with `uv`, but
|
||||
- *[Supported Systems](#supported-systems)*
|
||||
- Install Instructions
|
||||
- **[Option A. Docker / Docker Compose ⭐️](#option-a-docker--docker-compose-setup-%EF%B8%8F)**
|
||||
- [Option B. Automatic Setup Script](#option-b-automatic-setup-script)
|
||||
- [Option B. uv Install Shortcut](#option-b-uv-install-shortcut)
|
||||
- [Option C. System Package Manager Setup](#option-c-bare-metal-setup)
|
||||
- *[Upgrading ArchiveBox to a new version](#upgrading-archivebox-to-a-new-version)*
|
||||
- *[Next Steps](#next-steps)*
|
||||
@ -66,9 +66,9 @@ It's also recommended to use a filesystem with compression and/or [deduplication
|
||||
<br/>
|
||||
|
||||
|
||||
## Option B. Automatic Setup Script
|
||||
## Option B. uv Install Shortcut
|
||||
|
||||
If you're on macOS or Ubuntu, there is an optional auto-setup script provided.
|
||||
On macOS, Linux, or BSD, `get.archivebox.io` is a shortcut for the `uv` install method.
|
||||
|
||||
*(or scroll further down for manual install instructions)*
|
||||
|
||||
@ -76,9 +76,7 @@ If you're on macOS or Ubuntu, there is an optional auto-setup script provided.
|
||||
curl -fsSL 'https://get.archivebox.io' | bash
|
||||
# shortcut to run https://raw.githubusercontent.com/ArchiveBox/ArchiveBox/dev/bin/setup.sh
|
||||
```
|
||||
The script uses Docker Compose when available, otherwise plain Docker when it can pull the released image. If Docker is unavailable, it shows the native `uv` install plan and pauses so you can cancel before continuing. It initializes the collection, installs ArchiveBox's runtime dependencies, and starts the server. Open the printed Admin UI URL to create the first admin. If `BASE_URL` is not configured yet, continue through the web setup wizard.
|
||||
|
||||
Run it as your normal user unless you want a system-owned deployment. When run as root, the script creates the `archivebox` service user and places the collection under that account's home directory; it prints the exact path and follow-up commands when finished.
|
||||
The script installs `uv` when needed, then runs the same `uv tool install` command documented below. It does not initialize a collection, install runtime dependencies, or start a server; continue with the Quickstart after it finishes.
|
||||
|
||||
<img src="https://imgur.zervice.io/VMTzm0G.png" width="99%"/>
|
||||
|
||||
@ -94,7 +92,7 @@ After running the setup script, continue with the [Quickstart](https://github.co
|
||||
|
||||
## Option C. Bare Metal Setup
|
||||
|
||||
If you'd rather not use [Docker](https://github.com/ArchiveBox/ArchiveBox#%EF%B8%8F-easy-setup) or our [auto-install script](https://github.com/ArchiveBox/ArchiveBox#%EF%B8%8F-easy-setup), you can follow these manual setup instructions to install ArchiveBox and its dependencies using `uv`, `apt`, or Homebrew.
|
||||
If you'd rather not use [Docker](https://github.com/ArchiveBox/ArchiveBox#%EF%B8%8F-easy-setup) or our [`uv` install shortcut](https://github.com/ArchiveBox/ArchiveBox#%EF%B8%8F-easy-setup), you can follow these manual setup instructions to install ArchiveBox and its dependencies using `uv`, `apt`, or Homebrew.
|
||||
|
||||
See our [Dependencies](https://github.com/ArchiveBox/ArchiveBox#dependencies) documentation to see the full list of dependencies and how they're used. Not all the dependencies are required for all modes. If you disable some archive methods you can skip installing those dependencies — for example, if you set [`MEDIA_ENABLED=False`](https://archivebox.github.io/abx-plugins/#media) you don't need to install `yt-dlp`, and if you set [`PDF_ENABLED=False`](https://archivebox.github.io/abx-plugins/#pdf), [`SCREENSHOT_ENABLED=False`](https://archivebox.github.io/abx-plugins/#screenshot), and [`DOM_ENABLED=False`](https://archivebox.github.io/abx-plugins/#dom) you don't need `chromium`.
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user