From e604fdb2e7d1e32ee3de13b7e67d0b1266a6c03f Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Tue, 31 Mar 2026 12:52:20 +0400 Subject: [PATCH] Add cross-compilation, Linux binary build, and systemd service installer - Dockerfile.cross: builds static x86_64 musl binary from macOS via Docker - scripts/build-linux.sh: one-command cross-compilation - scripts/install-service.sh: systemd service with security hardening - Bump Rust Docker images to 1.86 for edition2024 support Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 1 + Dockerfile | 2 +- Dockerfile.cross | 17 ++++++ scripts/build-linux.sh | 17 ++++++ scripts/install-service.sh | 121 +++++++++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 Dockerfile.cross create mode 100755 scripts/build-linux.sh create mode 100755 scripts/install-service.sh diff --git a/.gitignore b/.gitignore index 194c6d1..474aae3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target +/dist btest_original .claude/ diff --git a/Dockerfile b/Dockerfile index 36cb10e..a0af9b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build -FROM rust:1.82-slim AS builder +FROM rust:1.86-slim AS builder WORKDIR /build COPY Cargo.toml Cargo.lock ./ diff --git a/Dockerfile.cross b/Dockerfile.cross new file mode 100644 index 0000000..c3c5c23 --- /dev/null +++ b/Dockerfile.cross @@ -0,0 +1,17 @@ +# Cross-compile for x86_64 Linux using an x86_64 builder (emulated via QEMU on ARM hosts) +FROM --platform=linux/amd64 rust:1.86-slim AS builder + +RUN apt-get update && apt-get install -y --no-install-recommends \ + musl-tools \ + && rustup target add x86_64-unknown-linux-musl \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build +COPY Cargo.toml Cargo.lock ./ +COPY src/ src/ + +RUN cargo build --release --target x86_64-unknown-linux-musl + +# Extract the binary +FROM scratch AS export +COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/btest /btest diff --git a/scripts/build-linux.sh b/scripts/build-linux.sh new file mode 100755 index 0000000..a4b3165 --- /dev/null +++ b/scripts/build-linux.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Build a static x86_64 Linux binary using Docker (works from macOS) +set -euo pipefail + +cd "$(dirname "$0")/.." + +echo "=== Building x86_64 Linux binary via Docker ===" +DOCKER_BUILDKIT=1 docker build \ + -f Dockerfile.cross \ + --output type=local,dest=./dist \ + . + +ls -lh dist/btest +file dist/btest +echo "" +echo "Binary ready at: dist/btest" +echo "Copy to your server: scp dist/btest user@server:/usr/local/bin/btest" diff --git a/scripts/install-service.sh b/scripts/install-service.sh new file mode 100755 index 0000000..84753b0 --- /dev/null +++ b/scripts/install-service.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +# Install btest as a systemd service on Linux +# Usage: sudo ./install-service.sh [--auth-user USER --auth-pass PASS] [--port PORT] +set -euo pipefail + +BTEST_BIN="/usr/local/bin/btest" +BTEST_USER="btest" +BTEST_PORT="2000" +AUTH_USER="" +AUTH_PASS="" + +while [[ $# -gt 0 ]]; do + case $1 in + --auth-user) AUTH_USER="$2"; shift 2 ;; + --auth-pass) AUTH_PASS="$2"; shift 2 ;; + --port) BTEST_PORT="$2"; shift 2 ;; + --help|-h) + echo "Usage: sudo $0 [OPTIONS]" + echo "" + echo "Options:" + echo " --auth-user USER Authentication username" + echo " --auth-pass PASS Authentication password" + echo " --port PORT Listen port (default: 2000)" + echo "" + echo "Examples:" + echo " sudo $0" + echo " sudo $0 --auth-user admin --auth-pass secret" + echo " sudo $0 --port 2000 --auth-user admin --auth-pass mypass" + exit 0 + ;; + *) echo "Unknown option: $1"; exit 1 ;; + esac +done + +if [[ $EUID -ne 0 ]]; then + echo "Error: This script must be run as root (use sudo)" + exit 1 +fi + +# Check binary exists +if [[ ! -f "$BTEST_BIN" ]]; then + # Try to find it in current directory or dist/ + if [[ -f "./btest" ]]; then + cp ./btest "$BTEST_BIN" + elif [[ -f "./dist/btest" ]]; then + cp ./dist/btest "$BTEST_BIN" + else + echo "Error: btest binary not found. Copy it to $BTEST_BIN first." + echo " scp dist/btest root@server:/usr/local/bin/btest" + exit 1 + fi +fi + +chmod +x "$BTEST_BIN" + +# Create service user +if ! id -u "$BTEST_USER" &>/dev/null; then + useradd --system --no-create-home --shell /usr/sbin/nologin "$BTEST_USER" + echo "Created system user: $BTEST_USER" +fi + +# Build ExecStart command +EXEC_START="$BTEST_BIN -s -P $BTEST_PORT" +if [[ -n "$AUTH_USER" ]]; then + EXEC_START="$EXEC_START -a $AUTH_USER" +fi +if [[ -n "$AUTH_PASS" ]]; then + EXEC_START="$EXEC_START -p $AUTH_PASS" +fi + +# Create systemd unit +cat > /etc/systemd/system/btest.service << UNIT +[Unit] +Description=MikroTik Bandwidth Test Server (btest) +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=$BTEST_USER +ExecStart=$EXEC_START +Restart=always +RestartSec=5 + +# Security hardening +NoNewPrivileges=yes +ProtectSystem=strict +ProtectHome=yes +PrivateTmp=yes +ProtectKernelTunables=yes +ProtectControlGroups=yes + +# Allow binding to port 2000 (< 1024 needs capability) +AmbientCapabilities=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE + +# Resource limits +LimitNOFILE=65535 + +[Install] +WantedBy=multi-user.target +UNIT + +echo "Created /etc/systemd/system/btest.service" + +# Reload and enable +systemctl daemon-reload +systemctl enable btest.service +systemctl restart btest.service + +echo "" +echo "=== btest service installed and started ===" +echo "" +systemctl status btest.service --no-pager +echo "" +echo "Useful commands:" +echo " systemctl status btest # Check status" +echo " systemctl stop btest # Stop" +echo " systemctl restart btest # Restart" +echo " journalctl -u btest -f # Follow logs" +echo " systemctl disable btest # Disable autostart"