├── .cargo └── config.toml ├── .github ├── install-arm-linkers.yml ├── renovate.json └── workflows │ ├── audit.yml │ ├── ci.yml │ ├── cross-ci.yml │ ├── lint-docs.yml │ ├── nightly.yml │ ├── prebuilt-pr.yml │ ├── release-image.yml │ ├── release-plz.yml │ ├── release.yml │ └── triage.yml ├── .gitignore ├── .justfile ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── Cross.toml ├── LICENSE ├── README.md ├── USAGE.md ├── build-dependencies.just ├── cliff.toml ├── committed.toml ├── config ├── README.md ├── acl.example.toml ├── rustic_profile.toml └── rustic_server.toml ├── containers ├── Dockerfile └── docker-compose.yml ├── deny.toml ├── dist-workspace.toml ├── dprint.json ├── maskfile.md ├── release-plz.toml ├── self_signed_certs └── .gitkeep ├── src ├── acl.rs ├── application.rs ├── auth.rs ├── bin │ └── rustic-server.rs ├── commands.rs ├── commands │ ├── auth.rs │ └── serve.rs ├── config.rs ├── context.rs ├── error.rs ├── handlers.rs ├── handlers │ ├── access_check.rs │ ├── file_config.rs │ ├── file_exchange.rs │ ├── file_helpers.rs │ ├── file_length.rs │ ├── files_list.rs │ ├── health.rs │ └── repository.rs ├── htpasswd.rs ├── lib.rs ├── log.rs ├── prelude.rs ├── snapshots │ ├── rustic_server__acl__tests__acl_default_impl.snap │ ├── rustic_server__acl__tests__repo_acl_passes.snap │ ├── rustic_server__config__test__config_parsing_from_file_passes.snap │ ├── rustic_server__config__test__default_config_passes.snap │ ├── rustic_server__config__test__file_read.snap │ ├── rustic_server__config__test__issue_60_parse_config_passes.snap │ ├── rustic_server__config__test__optional_explicit_parse_config_passes.snap │ ├── rustic_server__config__test__optional_implicit_parse_config_passes.snap │ ├── rustic_server__config__test__parse_config_passes.snap │ └── rustic_server__htpasswd__test__htpasswd_passes.snap ├── storage.rs ├── testing.rs ├── typed_path.rs └── web.rs ├── tests ├── fixtures │ ├── hurl │ │ └── endpoints.hurl │ └── test_data │ │ ├── .htpasswd │ │ ├── README.md │ │ ├── acl.toml │ │ ├── certs │ │ ├── test.crt │ │ └── test.key │ │ ├── rustic.toml │ │ ├── rustic_server.toml │ │ ├── server_acl_minimal.toml │ │ └── test_repo_source │ │ ├── my_file.html │ │ ├── my_file.txt │ │ └── my_folder │ │ ├── my_file.html │ │ ├── my_file.txt │ │ └── random_data.bin ├── generated │ └── test_storage │ │ └── test_repo │ │ ├── config │ │ └── keys │ │ └── 3f918b737a2b9f72f044d06d6009eb34e0e8d06668209be3ce86e5c18dac0295 └── integration │ ├── _impl.rs │ ├── acceptance.rs │ ├── config.rs │ └── main.rs └── wix └── main.wxs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustdocflags = ["--document-private-items"] 3 | # rustflags = "-C target-cpu=native -D warnings" 4 | # incremental = true 5 | 6 | [target.armv7-unknown-linux-gnueabihf] 7 | linker = "arm-linux-gnueabihf-gcc" 8 | 9 | [target.armv7-unknown-linux-musleabihf] 10 | linker = "arm-linux-gnueabihf-gcc" 11 | 12 | [target.aarch64-unknown-linux-gnu] 13 | linker = "aarch64-linux-gnu-gcc" 14 | 15 | [target.aarch64-unknown-linux-musl] 16 | linker = "aarch64-linux-gnu-gcc" 17 | 18 | [target.i686-unknown-linux-gnu] 19 | linker = "i686-linux-gnu-gcc" 20 | 21 | [env] 22 | CC_i686-unknown-linux-gnu = "i686-linux-gnu-gcc" 23 | CC_aarch64_unknown_linux_musl = "aarch64-linux-gnu-gcc" 24 | CC_armv7_unknown_linux_gnueabihf = "arm-linux-gnueabihf-gcc" 25 | CC_armv7_unknown_linux_musleabihf = "arm-linux-gnueabihf-gcc" 26 | -------------------------------------------------------------------------------- /.github/install-arm-linkers.yml: -------------------------------------------------------------------------------- 1 | - name: Install armv7 and aarch64 Linkers 2 | if: runner.os == 'Linux' 3 | run: | 4 | sudo apt install gcc-aarch64-linux-gnu 5 | sudo apt install gcc-arm-none-eabi 6 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["local>rustic-rs/.github:renovate-config"] 4 | } 5 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security audit 2 | 3 | on: 4 | pull_request: 5 | schedule: 6 | # Runs at 00:00 UTC everyday 7 | - cron: "0 0 * * *" 8 | push: 9 | paths: 10 | - "**/Cargo.toml" 11 | - "**/Cargo.lock" 12 | - "crates/**/Cargo.toml" 13 | - "crates/**/Cargo.lock" 14 | merge_group: 15 | types: [checks_requested] 16 | 17 | concurrency: 18 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 19 | cancel-in-progress: true 20 | 21 | jobs: 22 | audit: 23 | if: ${{ github.repository_owner == 'rustic-rs' }} 24 | name: Audit 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 29 | # Ensure that the latest version of Cargo is installed 30 | - name: Install Rust toolchain 31 | uses: dtolnay/rust-toolchain@1482605bfc5719782e1267fd0c0cc350fe7646b8 # v1 32 | with: 33 | toolchain: stable 34 | - uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2 35 | - uses: rustsec/audit-check@69366f33c96575abad1ee0dba8212993eecbe998 # v2.0.0 36 | with: 37 | token: ${{ secrets.GITHUB_TOKEN }} 38 | 39 | cargo-deny: 40 | if: ${{ github.repository_owner == 'rustic-rs' }} 41 | name: Run cargo-deny 42 | runs-on: ubuntu-latest 43 | steps: 44 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 45 | 46 | - uses: EmbarkStudios/cargo-deny-action@8371184bd11e21dcf8ac82ebf8c9c9f74ebf7268 # v2 47 | with: 48 | command: check bans licenses sources 49 | 50 | result: 51 | if: ${{ github.repository_owner == 'rustic-rs' }} 52 | name: Result (Audit) 53 | runs-on: ubuntu-latest 54 | needs: 55 | - audit 56 | - cargo-deny 57 | steps: 58 | - name: Mark the job as successful 59 | run: exit 0 60 | if: success() 61 | - name: Mark the job as unsuccessful 62 | run: exit 1 63 | if: "!success()" 64 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - "**/*.md" 7 | push: 8 | branches: 9 | - main 10 | - "renovate/**" 11 | paths-ignore: 12 | - "**/*.md" 13 | schedule: 14 | - cron: "0 0 * * 0" 15 | merge_group: 16 | types: [checks_requested] 17 | 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | fmt: 24 | name: Rustfmt 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 28 | - name: Install Rust toolchain 29 | uses: dtolnay/rust-toolchain@1482605bfc5719782e1267fd0c0cc350fe7646b8 # v1 30 | with: 31 | toolchain: stable 32 | components: rustfmt 33 | - name: Run Cargo Fmt 34 | run: cargo fmt --all -- --check 35 | 36 | clippy: 37 | name: Clippy 38 | runs-on: ubuntu-latest 39 | 40 | steps: 41 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 42 | - name: Install Rust toolchain 43 | uses: dtolnay/rust-toolchain@1482605bfc5719782e1267fd0c0cc350fe7646b8 # v1 44 | with: 45 | toolchain: stable 46 | components: clippy 47 | - uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2 48 | - name: Run clippy 49 | run: cargo clippy --all-targets --all-features -- -D warnings 50 | 51 | test: 52 | name: Test 53 | runs-on: ${{ matrix.job.os }} 54 | strategy: 55 | matrix: 56 | rust: [stable] 57 | job: 58 | - os: macos-latest 59 | - os: ubuntu-latest 60 | - os: windows-latest 61 | steps: 62 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 63 | if: github.event_name != 'pull_request' 64 | with: 65 | fetch-depth: 0 66 | 67 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 68 | if: github.event_name == 'pull_request' 69 | with: 70 | ref: ${{ github.event.pull_request.head.sha }} 71 | fetch-depth: 0 72 | 73 | - name: Install Rust toolchain 74 | uses: dtolnay/rust-toolchain@1482605bfc5719782e1267fd0c0cc350fe7646b8 # v1 75 | with: 76 | toolchain: stable 77 | - uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2 78 | - name: Run Cargo Test 79 | run: cargo test --all-targets --all-features --workspace 80 | 81 | result: 82 | name: Result (CI) 83 | runs-on: ubuntu-latest 84 | needs: 85 | - fmt 86 | - clippy 87 | - test 88 | steps: 89 | - name: Mark the job as successful 90 | run: exit 0 91 | if: success() 92 | - name: Mark the job as unsuccessful 93 | run: exit 1 94 | if: "!success()" 95 | -------------------------------------------------------------------------------- /.github/workflows/cross-ci.yml: -------------------------------------------------------------------------------- 1 | name: Cross CI 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - "**/*.md" 7 | push: 8 | branches: 9 | - main 10 | - "renovate/**" 11 | - "release/**" 12 | paths-ignore: 13 | - "**/*.md" 14 | merge_group: 15 | types: [checks_requested] 16 | 17 | defaults: 18 | run: 19 | shell: bash 20 | 21 | concurrency: 22 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 23 | cancel-in-progress: true 24 | 25 | jobs: 26 | cross-check: 27 | name: Cross checking ${{ matrix.job.target }} on ${{ matrix.rust }} 28 | runs-on: ${{ matrix.job.os }} 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | rust: [stable] 33 | job: 34 | - os: windows-latest 35 | os-name: windows 36 | target: x86_64-pc-windows-msvc 37 | architecture: x86_64 38 | use-cross: false 39 | - os: windows-latest 40 | os-name: windows 41 | target: x86_64-pc-windows-gnu 42 | architecture: x86_64 43 | use-cross: false 44 | - os: macos-13 45 | os-name: macos 46 | target: x86_64-apple-darwin 47 | architecture: x86_64 48 | use-cross: false 49 | - os: macos-latest 50 | os-name: macos 51 | target: aarch64-apple-darwin 52 | architecture: arm64 53 | use-cross: true 54 | - os: ubuntu-latest 55 | os-name: linux 56 | target: x86_64-unknown-linux-gnu 57 | architecture: x86_64 58 | use-cross: false 59 | - os: ubuntu-latest 60 | os-name: linux 61 | target: x86_64-unknown-linux-musl 62 | architecture: x86_64 63 | use-cross: false 64 | - os: ubuntu-latest 65 | os-name: linux 66 | target: aarch64-unknown-linux-gnu 67 | architecture: arm64 68 | use-cross: true 69 | - os: ubuntu-latest 70 | os-name: linux 71 | target: aarch64-unknown-linux-musl 72 | architecture: arm64 73 | use-cross: true 74 | - os: ubuntu-latest 75 | os-name: linux 76 | target: i686-unknown-linux-gnu 77 | architecture: i386 78 | use-cross: true 79 | - os: ubuntu-latest 80 | os-name: linux 81 | target: armv7-unknown-linux-gnueabihf 82 | architecture: armv7 83 | use-cross: true 84 | 85 | steps: 86 | - name: Checkout repository 87 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 88 | 89 | - name: Run Cross-CI action 90 | uses: rustic-rs/cross-ci-action@main 91 | with: 92 | toolchain: ${{ matrix.rust }} 93 | target: ${{ matrix.job.target }} 94 | use-cross: ${{ matrix.job.use-cross }} 95 | project-cache-key: "rustic_server" 96 | 97 | result: 98 | name: Result (Cross-CI) 99 | runs-on: ubuntu-latest 100 | needs: cross-check 101 | steps: 102 | - name: Mark the job as successful 103 | run: exit 0 104 | if: success() 105 | - name: Mark the job as unsuccessful 106 | run: exit 1 107 | if: "!success()" 108 | -------------------------------------------------------------------------------- /.github/workflows/lint-docs.yml: -------------------------------------------------------------------------------- 1 | name: Lint Markdown / Toml 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | merge_group: 8 | types: [checks_requested] 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | style: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 19 | 20 | - uses: dprint/check@2f1cf31537886c3bfb05591c031f7744e48ba8a1 # v2.2 21 | 22 | result: 23 | name: Result (Style) 24 | runs-on: ubuntu-latest 25 | needs: 26 | - style 27 | steps: 28 | - name: Mark the job as successful 29 | run: exit 0 30 | if: success() 31 | - name: Mark the job as unsuccessful 32 | run: exit 1 33 | if: "!success()" 34 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Deployment 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # “At 00:10.” 7 | # https://crontab.guru/#10_0_*_*_* 8 | - cron: "10 0 * * *" 9 | 10 | defaults: 11 | run: 12 | shell: bash 13 | 14 | env: 15 | BINARY_NAME: rustic-server 16 | BINARY_NIGHTLY_DIR: rustic_server 17 | 18 | jobs: 19 | publish: 20 | if: ${{ github.repository_owner == 'rustic-rs' && github.ref == 'refs/heads/main' }} 21 | name: Publishing ${{ matrix.job.target }} 22 | runs-on: ${{ matrix.job.os }} 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | rust: [stable] 27 | job: 28 | - os: windows-latest 29 | os-name: windows 30 | target: x86_64-pc-windows-msvc 31 | architecture: x86_64 32 | binary-postfix: ".exe" 33 | use-cross: false 34 | - os: windows-latest 35 | os-name: windows 36 | target: x86_64-pc-windows-gnu 37 | architecture: x86_64 38 | binary-postfix: ".exe" 39 | use-cross: false 40 | - os: macos-13 41 | os-name: macos 42 | target: x86_64-apple-darwin 43 | architecture: x86_64 44 | binary-postfix: "" 45 | use-cross: false 46 | - os: macos-latest 47 | os-name: macos 48 | target: aarch64-apple-darwin 49 | architecture: arm64 50 | binary-postfix: "" 51 | use-cross: false 52 | - os: ubuntu-latest 53 | os-name: linux 54 | target: x86_64-unknown-linux-gnu 55 | architecture: x86_64 56 | binary-postfix: "" 57 | use-cross: false 58 | - os: ubuntu-latest 59 | os-name: linux 60 | target: x86_64-unknown-linux-musl 61 | architecture: x86_64 62 | binary-postfix: "" 63 | use-cross: false 64 | - os: ubuntu-latest 65 | os-name: linux 66 | target: aarch64-unknown-linux-gnu 67 | architecture: arm64 68 | binary-postfix: "" 69 | use-cross: true 70 | - os: ubuntu-latest 71 | os-name: linux 72 | target: aarch64-unknown-linux-musl 73 | architecture: arm64 74 | binary-postfix: "" 75 | use-cross: true 76 | - os: ubuntu-latest 77 | os-name: linux 78 | target: i686-unknown-linux-gnu 79 | architecture: i386 80 | binary-postfix: "" 81 | use-cross: true 82 | - os: ubuntu-latest 83 | os-name: linux 84 | target: armv7-unknown-linux-gnueabihf 85 | architecture: armv7 86 | binary-postfix: "" 87 | use-cross: true 88 | 89 | steps: 90 | - name: Checkout repository 91 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 92 | with: 93 | fetch-depth: 0 # fetch all history so that git describe works 94 | - name: Create binary artifact 95 | uses: rustic-rs/create-binary-artifact-action@main # dev 96 | with: 97 | toolchain: ${{ matrix.rust }} 98 | target: ${{ matrix.job.target }} 99 | use-cross: ${{ matrix.job.use-cross }} 100 | describe-tag-suffix: -nightly 101 | binary-postfix: ${{ matrix.job.binary-postfix }} 102 | os: ${{ runner.os }} 103 | binary-name: ${{ env.BINARY_NAME }} 104 | package-secondary-name: nightly-${{ matrix.job.target}} 105 | github-token: ${{ secrets.GITHUB_TOKEN }} 106 | gpg-release-private-key: ${{ secrets.GPG_RELEASE_PRIVATE_KEY }} 107 | gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} 108 | rsign-release-private-key: ${{ secrets.RSIGN_RELEASE_PRIVATE_KEY }} 109 | rsign-passphrase: ${{ secrets.RSIGN_PASSPHRASE }} 110 | github-ref: ${{ github.ref }} 111 | sign-release: true 112 | hash-release: true 113 | use-project-version: false 114 | 115 | publish-nightly: 116 | if: ${{ github.repository_owner == 'rustic-rs' && github.ref == 'refs/heads/main' }} 117 | name: Publishing nightly builds 118 | needs: publish 119 | runs-on: ubuntu-latest 120 | steps: 121 | - name: Download all workflow run artifacts 122 | uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 123 | - name: Releasing nightly builds 124 | shell: bash 125 | run: | 126 | # set up some directories 127 | WORKING_DIR=$(mktemp -d) 128 | DEST_DIR=$BINARY_NIGHTLY_DIR 129 | 130 | # set up the github deploy key 131 | mkdir -p ~/.ssh 132 | echo "${{ secrets.NIGHTLY_RELEASE_KEY }}" > ~/.ssh/id_ed25519 133 | chmod 600 ~/.ssh/id_ed25519 134 | 135 | # set up git 136 | git config --global user.name "${{ github.actor }}" 137 | git config --global user.email "${{ github.actor }}" 138 | ssh-keyscan -H github.com > ~/.ssh/known_hosts 139 | GIT_SSH='ssh -i ~/.ssh/id_ed25519 -o UserKnownHostsFile=~/.ssh/known_hosts' 140 | 141 | # clone the repo into our working directory 142 | # we use --depth 1 to avoid cloning the entire history 143 | # and only the main branch to avoid cloning all branches 144 | GIT_SSH_COMMAND=$GIT_SSH git clone git@github.com:rustic-rs/nightly.git --branch main --single-branch --depth 1 $WORKING_DIR 145 | 146 | # ensure destination directory exists 147 | mkdir -p $WORKING_DIR/$DEST_DIR 148 | 149 | # do the copy 150 | for i in binary-*; do cp -a $i/* $WORKING_DIR/$DEST_DIR; done 151 | 152 | # create the commit 153 | cd $WORKING_DIR 154 | git add . 155 | git commit -m "${{ github.job }} from https://github.com/${{ github.repository }}/commit/${{ github.sha }}" || echo 156 | GIT_SSH_COMMAND=$GIT_SSH git pull --rebase 157 | GIT_SSH_COMMAND=$GIT_SSH git push 158 | -------------------------------------------------------------------------------- /.github/workflows/prebuilt-pr.yml: -------------------------------------------------------------------------------- 1 | name: Create PR artifacts 2 | 3 | on: 4 | pull_request: 5 | types: [labeled] 6 | branches: 7 | - main 8 | paths-ignore: 9 | - "**/*.md" 10 | - "docs/**/*" 11 | workflow_dispatch: 12 | 13 | env: 14 | BINARY_NAME: rustic-server 15 | 16 | concurrency: 17 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | pr-build: 22 | if: ${{ github.event.label.name == 'S-build' && github.repository_owner == 'rustic-rs' }} 23 | name: Build PR on ${{ matrix.job.target }} 24 | runs-on: ${{ matrix.job.os }} 25 | strategy: 26 | matrix: 27 | rust: [stable] 28 | job: 29 | - os: windows-latest 30 | os-name: windows 31 | target: x86_64-pc-windows-msvc 32 | architecture: x86_64 33 | binary-postfix: ".exe" 34 | use-cross: false 35 | - os: macos-13 36 | os-name: macos 37 | target: x86_64-apple-darwin 38 | architecture: x86_64 39 | binary-postfix: "" 40 | use-cross: false 41 | - os: macos-latest 42 | os-name: macos 43 | target: aarch64-apple-darwin 44 | architecture: arm64 45 | binary-postfix: "" 46 | use-cross: false 47 | - os: ubuntu-latest 48 | os-name: linux 49 | target: x86_64-unknown-linux-gnu 50 | architecture: x86_64 51 | binary-postfix: "" 52 | use-cross: false 53 | - os: ubuntu-latest 54 | os-name: linux 55 | target: x86_64-unknown-linux-musl 56 | architecture: x86_64 57 | binary-postfix: "" 58 | use-cross: false 59 | - os: ubuntu-latest 60 | os-name: linux 61 | target: aarch64-unknown-linux-gnu 62 | architecture: arm64 63 | binary-postfix: "" 64 | use-cross: true 65 | - os: ubuntu-latest 66 | os-name: linux 67 | target: aarch64-unknown-linux-musl 68 | architecture: arm64 69 | binary-postfix: "" 70 | use-cross: true 71 | - os: ubuntu-latest 72 | os-name: linux 73 | target: i686-unknown-linux-gnu 74 | architecture: i386 75 | binary-postfix: "" 76 | use-cross: true 77 | - os: ubuntu-latest 78 | os-name: linux 79 | target: armv7-unknown-linux-gnueabihf 80 | architecture: armv7 81 | binary-postfix: "" 82 | use-cross: true 83 | 84 | steps: 85 | - name: Checkout repository 86 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 87 | with: 88 | fetch-depth: 0 # fetch all history so that git describe works 89 | - name: Create binary artifact 90 | uses: rustic-rs/create-binary-artifact-action@main # dev 91 | with: 92 | toolchain: ${{ matrix.rust }} 93 | target: ${{ matrix.job.target }} 94 | use-cross: ${{ matrix.job.use-cross }} 95 | describe-tag-suffix: -${{ github.run_id }}-${{ github.run_attempt }} 96 | binary-postfix: ${{ matrix.job.binary-postfix }} 97 | os: ${{ runner.os }} 98 | binary-name: ${{ env.BINARY_NAME }} 99 | package-secondary-name: ${{ matrix.job.target}} 100 | github-token: ${{ secrets.GITHUB_TOKEN }} 101 | github-ref: ${{ github.ref }} 102 | sign-release: false 103 | hash-release: true 104 | use-project-version: false # not being used in rustic_server 105 | 106 | remove-build-label: 107 | name: Remove build label 108 | needs: pr-build 109 | permissions: 110 | contents: read 111 | issues: write 112 | pull-requests: write 113 | runs-on: ubuntu-latest 114 | if: | 115 | always() && 116 | ! contains(needs.*.result, 'skipped') && 117 | github.repository_owner == 'rustic-rs' 118 | steps: 119 | - name: Remove label 120 | env: 121 | GH_TOKEN: ${{ github.token }} 122 | run: | 123 | gh api \ 124 | --method DELETE \ 125 | -H "Accept: application/vnd.github+json" \ 126 | -H "X-GitHub-Api-Version: 2022-11-28" \ 127 | /repos/${{ github.repository }}/issues/${{ github.event.number }}/labels/S-build 128 | -------------------------------------------------------------------------------- /.github/workflows/release-image.yml: -------------------------------------------------------------------------------- 1 | name: Release Docker Image 2 | 3 | on: [release] 4 | 5 | jobs: 6 | docker: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Set up Docker Buildx 10 | uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3 11 | 12 | - name: Login to Docker Hub 13 | uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 14 | with: 15 | registry: ghcr.io 16 | username: ${{ github.actor }} 17 | password: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | - name: Build and push 20 | uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6 21 | with: 22 | context: "{{defaultContext}}:containers" 23 | push: true 24 | platforms: linux/amd64,linux/arm64 25 | tags: ghcr.io/rustic-rs/rustic_server:latest,ghcr.io/rustic-rs/rustic_server:${{ github.ref_name }} 26 | build-args: RUSTIC_SERVER_VERSION=${{ github.ref_name }} 27 | -------------------------------------------------------------------------------- /.github/workflows/release-plz.yml: -------------------------------------------------------------------------------- 1 | name: Release-plz 2 | 3 | permissions: 4 | pull-requests: write 5 | contents: write 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | release-plz: 14 | name: Release-plz 15 | if: ${{ github.repository_owner == 'rustic-rs' }} 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Generate GitHub token 19 | uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1 20 | id: generate-token 21 | with: 22 | app-id: ${{ secrets.RELEASE_PLZ_APP_ID }} 23 | private-key: ${{ secrets.RELEASE_PLZ_APP_PRIVATE_KEY }} 24 | - name: Checkout repository 25 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 26 | with: 27 | fetch-depth: 0 28 | token: ${{ steps.generate-token.outputs.token }} 29 | - name: Install Rust toolchain 30 | uses: dtolnay/rust-toolchain@stable 31 | 32 | - name: Run release-plz 33 | uses: MarcoIeni/release-plz-action@301fd6d8c641b97f25b5ade37651a478a5faa7da # v0.5 34 | env: 35 | GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} 36 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/triage.yml: -------------------------------------------------------------------------------- 1 | on: 2 | issues: 3 | types: 4 | - opened 5 | 6 | jobs: 7 | label_issue: 8 | if: ${{ github.repository_owner == 'rustic-rs' }} 9 | name: Label issue 10 | runs-on: ubuntu-latest 11 | steps: 12 | - env: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | ISSUE_URL: ${{ github.event.issue.html_url }} 15 | run: | 16 | # check if issue doesn't have any labels 17 | if [[ $(gh issue view $ISSUE_URL --json labels -q '.labels | length') -eq 0 ]]; then 18 | # add S-triage label 19 | gh issue edit $ISSUE_URL --add-label "S-triage" 20 | fi 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | # Generated by Cargo 3 | # will have compiled files and executables 4 | /target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # IDE files 10 | .idea 11 | .vscode 12 | 13 | # Test data created may accidentally be included 14 | tests/fixtures/rest_server 15 | repo_remove_me* 16 | __* 17 | ci_repo 18 | repo_not_* 19 | containers/volumes -------------------------------------------------------------------------------- /.justfile: -------------------------------------------------------------------------------- 1 | # 'Just' Configuration 2 | # Loads .env file for variables to be used in 3 | # in this just file 4 | 5 | set dotenv-load := true 6 | 7 | # Ignore recipes that are commented out 8 | 9 | set ignore-comments := true 10 | 11 | # Set shell for Windows OSs: 12 | # If you have PowerShell Core installed and want to use it, 13 | # use `pwsh.exe` instead of `powershell.exe` 14 | 15 | set windows-shell := ["powershell.exe", "-NoLogo", "-Command"] 16 | 17 | # Set shell for non-Windows OSs: 18 | 19 | set shell := ["bash", "-uc"] 20 | 21 | export RUST_BACKTRACE := "1" 22 | export RUST_LOG := "" 23 | export CI := "1" 24 | 25 | build: 26 | cargo build --all-features 27 | cargo build -r --all-features 28 | 29 | b: build 30 | 31 | check: 32 | cargo check --no-default-features 33 | cargo check --all-features 34 | 35 | c: check 36 | 37 | ci: 38 | just loop . dev 39 | 40 | dev: format lint test 41 | 42 | d: dev 43 | 44 | format-dprint: 45 | dprint fmt 46 | 47 | format-cargo: 48 | cargo fmt --all 49 | 50 | format: format-cargo format-dprint 51 | 52 | fmt: format 53 | 54 | rev: 55 | cargo insta review 56 | 57 | inverse-deps crate: 58 | cargo tree -e features -i {{ crate }} 59 | 60 | lint: check 61 | cargo clippy --no-default-features -- -D warnings 62 | cargo clippy --all-targets --all-features -- -D warnings 63 | 64 | loop dir action: 65 | watchexec -w {{ dir }} -- "just {{ action }}" 66 | 67 | test: check lint 68 | cargo test --all-targets --all-features --workspace 69 | 70 | test-ignored: check lint 71 | cargo test --all-targets --all-features --workspace -- --ignored 72 | 73 | t: test test-ignored 74 | 75 | test-restic $RESTIC_REPOSITORY="rest:http://restic:restic@127.0.0.1:8080/ci_repo" $RESTIC_PASSWORD="restic": 76 | restic init 77 | restic backup tests/fixtures/test_data/test_repo_source 78 | restic backup src 79 | restic check 80 | restic forget --keep-last 1 --prune 81 | restic snapshots 82 | 83 | test-server: 84 | cargo run -- serve -c tests/fixtures/test_data/rustic_server.toml -v 85 | 86 | test-restic-server: 87 | tests/fixtures/rest_server/rest-server.exe --path ./tests/generated/test_storage/ --htpasswd-file ./tests/fixtures/test_data/.htpasswd --log ./tests/fixtures/rest_server/response2.log 88 | 89 | loop-test-server: 90 | watchexec --stop-signal "CTRL+C" -r -w src -w tests -- "cargo run -- serve -c tests/fixtures/test_data/rustic_server.toml -v" 91 | 92 | hurl: 93 | hurl -i tests/fixtures/hurl/endpoints.hurl 94 | 95 | dbg-test test_name $RUST_LOG="debug": 96 | cargo test --package rustic_server --lib -- {{ test_name }} --exact --nocapture --show-output 97 | 98 | build-docker version="0.4.0": 99 | podman build containers --build-arg RUSTIC_SERVER_VERSION=v{{ version }} --format docker --tag rustic_server:v{{ version }} 100 | 101 | server-up: build-docker 102 | uv --directory containers run podman-compose -f docker-compose.yml up --detach 103 | 104 | server-down: 105 | uv --directory containers run podman-compose -f docker-compose.yml down 106 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [0.4.4](https://github.com/rustic-rs/rustic_server/compare/v0.4.3...v0.4.4) - 2024-11-29 6 | 7 | ### Other 8 | 9 | - add targets ([#72](https://github.com/rustic-rs/rustic_server/pull/72)) 10 | 11 | ## [0.4.3](https://github.com/rustic-rs/rustic_server/compare/v0.4.2...v0.4.3) - 2024-11-27 12 | 13 | ### Added 14 | 15 | - enhance cross-check workflow with additional target configurations and enable cross-compilation for specific platforms ([#70](https://github.com/rustic-rs/rustic_server/pull/70)) 16 | 17 | ## [0.4.2](https://github.com/rustic-rs/rustic_server/compare/v0.4.1...v0.4.2) - 2024-11-26 18 | 19 | ### Other 20 | 21 | - update Cargo.lock dependencies 22 | 23 | ## [0.4.1](https://github.com/rustic-rs/rustic_server/compare/v0.4.0...v0.4.1) - 2024-11-23 24 | 25 | ### Added 26 | 27 | - update conflate dependency to version 0.3.2 and refactor merge strategies 28 | 29 | ### Other 30 | 31 | - add workspace linting configuration 32 | 33 | ## [0.4.0](https://github.com/rustic-rs/rustic_server/compare/v0.3.0...v0.4.0) - 2024-11-17 34 | 35 | ### Added 36 | 37 | - read more cli options from environment variables 38 | - add /health route(s) 39 | 40 | ### Other 41 | 42 | - set CI in test to run also locally in CI mode 43 | 44 | ## [0.3.0](https://github.com/rustic-rs/rustic_server/compare/v0.2.0...v0.3.0) - 2024-11-16 45 | 46 | ### Added 47 | 48 | - add context module and update configuration files 49 | 50 | ### Other 51 | 52 | - preparing the docs for another release 53 | - *(readme)* update readme for current state 54 | - some fixes applied to testing 55 | 56 | ## [0.2.0](https://github.com/rustic-rs/rustic_server/compare/v0.1.1...v0.2.0) - 2024-11-14 57 | 58 | ### Other 59 | 60 | - update readme 61 | - [**breaking**] move to axum - Part II ([#56](https://github.com/rustic-rs/rustic_server/pull/56)) 62 | 63 | ## [0.1.1] - 2024-01-09 64 | 65 | ### Bug Fixes 66 | 67 | - Nightly builds, exclude arm64 darwin build until issue Publishing 68 | aarch64-apple-darwin failed #6 is fixed 69 | - Update rust crate toml to 0.8 70 | - Deserialization with newest toml 71 | - Clippy 72 | - Remove unmaintained `actions-rs` ci actions 73 | - Update rust crate clap to 4.4.10 74 | ([#37](https://github.com/rustic-rs/rustic_server/issues/37)) 75 | - Update github action to download artifacts, as upload/download actions from 76 | nightly workflow were incompatible with each other 77 | - Don't unwrap in bin 78 | - Imports 79 | 80 | ### Documentation 81 | 82 | - Update readme, fix manifest 83 | - Add continuous deployment badge to readme 84 | - Fix typo in html element 85 | - Add link to nightly 86 | - Add link to nightly downloads in documentation 87 | - Remove CI Todo 88 | - Remove To-dos from Readme 89 | - Break line in toml code for usability 90 | - Update changelog 91 | - Rewrite contributing remark 92 | - Fix list indent 93 | - Add contributing 94 | - Remove tide remarks from readme 95 | 96 | ### Features 97 | 98 | - Pr-build flag to build artifacts for a pr manually if needed 99 | 100 | ### Miscellaneous Tasks 101 | 102 | - Add ci 103 | - Nightly builds 104 | - Update header link 105 | - Add release pr workflow 106 | - Add caching 107 | - Add signature and shallow clones to nightly 108 | - Declutter and reorganize 109 | - Remove lint from ci workflow and keep it separate, replace underscore in 110 | workflow files 111 | - Rebase and extract action to own repository 112 | - Use create-binary-artifact action 113 | - Put action version to follow main branch while action is still in development 114 | - Switch ci to rustic-rs/create-binary-artifact action 115 | - Switch rest of ci to rustic-rs/create-binary-artifact action 116 | - Change license 117 | - Fix workflow name for create-binary-artifact action, and check breaking 118 | changes package dependent 119 | - Decrease build times on windows 120 | - Fix github refs 121 | - Set right package 122 | - Use bash substring comparison to determine package name from branch 123 | - Fix woggly github action comparison 124 | - Add changelog generation 125 | - Initialize cargo release, update changelog 126 | - Add dev tooling 127 | - Run git-cliff with latest tag during release 128 | - Remove comment from cargo manifest 129 | - Change workflow extensions to yml 130 | - Add triaging of issues 131 | - Run release checks also on release subbranches 132 | - Add maskfile 133 | - Update changelog 134 | - Run workflow on renovate branches 135 | - Add merge queue checks 136 | - Add cargo deny 137 | - Relink to new image location 138 | - Add binstall support 139 | - Build nightly with rsign signed binaries 140 | - Update public key 141 | - Support rsign signature 142 | - Remove special os-dependent linker/compiler settings 143 | - Update cross ci 144 | - Check if nightly builds for arm64 darwin builds work now 145 | - Arm64 on darwin still fails 146 | - Add x86_64-pc-windows-gnu target 147 | - Compile dependencies with optimizations in dev mode 148 | - Add results to ci 149 | - Lockfile maintenance 150 | - Run actions that need secrets.GITHUB_TOKEN only on rustic-rs org 151 | - Update dtolnay/rust-toolchain 152 | - Update taiki-e/install-action 153 | - Update rustsec/audit-check 154 | - Netbsd nightly builds fail due to missing execinfo, so we don't build on it 155 | for now 156 | - Upgrade dprint config 157 | - Activate automerge for github action digest update 158 | - Activate automerge for github action digest update 159 | - Automerge lockfile maintenance 160 | - :debug 161 | - Update to latest axum and apply fixes 162 | - Reactivate audit workflow 163 | - Remove OnceCell dep and set rust-version 164 | - Remove justfile 165 | 166 | ### Refactor 167 | 168 | - Refactor to library and server binary 169 | - Begin refactor to axum 170 | - [**breaking**] Moving to axum 171 | ([#40](https://github.com/rustic-rs/rustic_server/issues/40)) 172 | - Use own errors throughout library part 173 | - State better which file is not able to be read 174 | - More error handling stuff 175 | 176 | ### Testing 177 | 178 | - Fix config tests 179 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `rustic_server` 2 | 3 | Thank you for your interest in contributing to `rustic_server`! 4 | 5 | We appreciate your help in making this project better. 6 | 7 | Please read the 8 | [contribution guide](https://rustic.cli.rs/docs/contributing-to-rustic.html) to 9 | get started. 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustic_server" 3 | version = "0.4.4" 4 | authors = ["the rustic-rs team"] 5 | categories = ["command-line-utilities"] 6 | edition = "2021" 7 | homepage = "https://rustic.cli.rs/" 8 | include = [ 9 | "src/**/*", 10 | "config/**/*", 11 | "Cargo.toml", 12 | "Cargo.lock", 13 | "LICENSE", 14 | "README.md", 15 | ] 16 | keywords = ["backup", "restic", "cli", "server"] 17 | license = "AGPL-3.0-or-later" 18 | repository = "https://github.com/rustic-rs/rustic_server" 19 | rust-version = "1.74.0" 20 | description = """ 21 | rustic server - a REST server built in rust to use with rustic and restic. 22 | """ 23 | # cargo-binstall support 24 | # https://github.com/cargo-bins/cargo-binstall/blob/HEAD/SUPPORT.md 25 | [package.metadata.binstall] 26 | pkg-url = "{ repo }/releases/download/v{ version }/{ repo }-v{ version }-{ target }{ archive-suffix }" 27 | bin-dir = "{ bin }-{ target }/{ bin }{ binary-ext }" 28 | pkg-fmt = "tar.gz" 29 | 30 | [package.metadata.binstall.signing] 31 | algorithm = "minisign" 32 | pubkey = "RWSWSCEJEEacVeCy0va71hlrVtiW8YzMzOyJeso0Bfy/ZXq5OryWi/8T" 33 | 34 | [package.metadata.wix] 35 | upgrade-guid = "EE4ED7D1-CE20-4919-B988-33482C0C3042" 36 | path-guid = "F5605741-D1CF-45E2-B082-3A71B58C01C8" 37 | license = false 38 | eula = false 39 | 40 | [dependencies] 41 | abscissa_tokio = "0.8.0" 42 | anyhow = "1" 43 | async-trait = "0.1" 44 | axum = { version = "0.7", features = ["tracing", "multipart", "http2", "macros"] } 45 | axum-auth = "0.7" 46 | axum-extra = { version = "0.9", features = ["typed-header", "query", "async-read-body", "typed-routing", "erased-json"] } 47 | axum-macros = "0.4" 48 | axum-range = "0.4" 49 | axum-server = { version = "0.7", features = ["tls-rustls-no-provider"] } 50 | chrono = { version = "0.4.38", features = ["serde"] } 51 | clap = { version = "4", features = ["derive", "env", "wrap_help"] } 52 | conflate = "0.3.3" 53 | displaydoc = "0.2" 54 | # enum_dispatch = "0.3.12" 55 | futures = "0.3" 56 | futures-util = "0.3" 57 | htpasswd-verify = "0.3" 58 | http-body-util = "0.1" 59 | http-range = "0.1" 60 | inquire = "0.7" 61 | pin-project = "1" 62 | rand = "0.8" 63 | serde = { version = "1", default-features = false, features = ["derive"] } 64 | serde_derive = "1" 65 | strum = { version = "0.26", features = ["derive"] } 66 | thiserror = "2" 67 | tokio = { version = "1", features = ["full"] } 68 | tokio-util = { version = "0.7", features = ["io", "io-util"] } 69 | toml = "0.8" 70 | tracing = "0.1" 71 | tracing-subscriber = { version = "0.3", features = ["env-filter"] } 72 | uuid = { version = "1.11.0", features = ["v4"] } 73 | walkdir = "2" 74 | 75 | [dependencies.abscissa_core] 76 | version = "0.8.1" 77 | # optional: use `gimli` to capture backtraces 78 | # see https://github.com/rust-lang/backtrace-rs/issues/189 79 | # features = ["gimli-backtrace"] 80 | 81 | [dependencies.rustls] 82 | version = "0.23.17" 83 | features = ["logging", "std", "ring", "tls12"] 84 | default-features = false 85 | 86 | [dev-dependencies] 87 | abscissa_core = { version = "0.8.1", features = ["testing"] } 88 | anyhow = "1" 89 | assert_cmd = "2" 90 | base64 = "0.22" 91 | dircmp = "0.2" 92 | insta = { version = "1", features = ["redactions", "toml"] } 93 | once_cell = "1.20" 94 | predicates = "3.1.2" 95 | pretty_assertions = "1" 96 | rstest = "0.23" 97 | serde_json = "1" 98 | # reqwest = "0.11.18" 99 | serial_test = { version = "3.2.0", features = ["file_locks"] } 100 | tower = "0.5" 101 | 102 | # see: https://nnethercote.github.io/perf-book/build-configuration.html 103 | [profile.dev] 104 | opt-level = 0 105 | debug = true 106 | rpath = false 107 | lto = false 108 | debug-assertions = true 109 | codegen-units = 4 110 | 111 | # compile dependencies with optimizations in dev mode 112 | # see: https://doc.rust-lang.org/stable/cargo/reference/profiles.html#overrides 113 | [profile.dev.package."*"] 114 | opt-level = 3 115 | debug = true 116 | 117 | [profile.release] 118 | opt-level = 3 119 | debug = false # true for profiling 120 | rpath = false 121 | lto = "fat" 122 | debug-assertions = false 123 | codegen-units = 1 124 | strip = true 125 | panic = "abort" 126 | 127 | [profile.test] 128 | opt-level = 1 129 | debug = true 130 | rpath = false 131 | lto = false 132 | debug-assertions = true 133 | codegen-units = 4 134 | 135 | [profile.bench] 136 | opt-level = 3 137 | debug = true # true for profiling 138 | rpath = false 139 | lto = true 140 | debug-assertions = false 141 | codegen-units = 1 142 | 143 | # The profile that 'dist' will build with 144 | [profile.dist] 145 | inherits = "release" 146 | lto = "thin" 147 | 148 | [workspace.lints.rust] 149 | unsafe_code = "forbid" 150 | missing_docs = "warn" 151 | rust_2018_idioms = { level = "warn", priority = -1 } 152 | trivial_casts = "warn" 153 | unused_lifetimes = "warn" 154 | unused_qualifications = "warn" 155 | bad_style = "warn" 156 | dead_code = "allow" # TODO: "warn" 157 | improper_ctypes = "warn" 158 | missing_copy_implementations = "warn" 159 | missing_debug_implementations = "warn" 160 | non_shorthand_field_patterns = "warn" 161 | no_mangle_generic_items = "warn" 162 | overflowing_literals = "warn" 163 | path_statements = "warn" 164 | patterns_in_fns_without_body = "warn" 165 | trivial_numeric_casts = "warn" 166 | unused_results = "warn" 167 | unused_extern_crates = "warn" 168 | unused_import_braces = "warn" 169 | unconditional_recursion = "warn" 170 | unused = { level = "warn", priority = -1 } 171 | unused_allocation = "warn" 172 | unused_comparisons = "warn" 173 | unused_parens = "warn" 174 | while_true = "warn" 175 | unreachable_pub = "allow" 176 | non_local_definitions = "allow" 177 | 178 | [workspace.lints.clippy] 179 | redundant_pub_crate = "allow" 180 | pedantic = { level = "warn", priority = -1 } 181 | nursery = { level = "warn", priority = -1 } 182 | # expect_used = "warn" # TODO! 183 | # unwrap_used = "warn" # TODO! 184 | enum_glob_use = "warn" 185 | correctness = { level = "warn", priority = -1 } 186 | suspicious = { level = "warn", priority = -1 } 187 | complexity = { level = "warn", priority = -1 } 188 | perf = { level = "warn", priority = -1 } 189 | cast_lossless = "warn" 190 | default_trait_access = "warn" 191 | doc_markdown = "warn" 192 | manual_string_new = "warn" 193 | match_same_arms = "warn" 194 | semicolon_if_nothing_returned = "warn" 195 | trivially_copy_pass_by_ref = "warn" 196 | module_name_repetitions = "allow" 197 | # TODO: Remove when Windows support landed 198 | # mostly Windows-related functionality is missing `const` 199 | # as it's only OK(()), but doesn't make it reasonable to 200 | # have a breaking change in the future. They won't be const. 201 | missing_const_for_fn = "allow" 202 | needless_raw_string_hashes = "allow" 203 | 204 | [workspace.lints.rustdoc] 205 | # We run rustdoc with `--document-private-items` so we can document private items 206 | private_intra_doc_links = "allow" 207 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [target.i686-unknown-linux-gnu] 2 | image = "ghcr.io/cross-rs/i686-unknown-linux-gnu:edge" 3 | pre-build = [ 4 | "dpkg --add-architecture $CROSS_DEB_ARCH", 5 | "apt-get update && apt-get --assume-yes install gcc-multilib-i686-linux-gnu gcc-i686-linux-gnu", 6 | ] 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
REST server for rustic
5 |11 |
15 | 16 | # ⚠️ This project is in early development and not yet ready for production use 17 | 18 | For now, expect bugs, breaking changes, and a lot of refactoring. 19 | 20 | Please feel free to contribute to this project, we are happy to help you getting 21 | started. Join our [Discord](https://discord.gg/WRUWENZnzQ) to get in touch with 22 | us. 23 | 24 | ## About 25 | 26 | A REST server built in rust for use with rustic and rustic. 27 | 28 | Works pretty similar to [rest-server](https://github.com/restic/rest-server). 29 | Most features are already implemented. 30 | 31 | ## Contact 32 | 33 | | Contact | Where? | 34 | | ------------- | --------------------------------------------------------------------------------------------- | 35 | | Issue Tracker | [GitHub Issues](https://github.com/rustic-rs/rustic_server/issues) | 36 | | Discord | [](https://discord.gg/WRUWENZnzQ) | 37 | | Discussions | [GitHub Discussions](https://github.com/rustic-rs/rustic/discussions) | 38 | 39 | ## Are binaries available? 40 | 41 | Yes, you can find them [here](https://rustic.cli.rs/docs/nightly_builds.html). 42 | 43 | ## Installation 44 | 45 | You can install `rustic-server` using `cargo`: 46 | 47 | ```console 48 | cargo install rustic_server 49 | ``` 50 | 51 | or you can download the binaries from the 52 | [releases page](https://github.com/rustic-rs/rustic_server/releases). 53 | 54 | ## Usage 55 | 56 | After installing `rustic-server`, you can start the server with the following 57 | command: 58 | 59 | ```console 60 | rustic-server serve 61 | ``` 62 | 63 | For more information, please refer to the 64 | [`rustic-server` usage documentation](https://github.com/rustic-rs/rustic_server/blob/main/USAGE.md). 65 | 66 | ## Contributing 67 | 68 | Tried rustic-server and not satisfied? Don't just walk away! You can help: 69 | 70 | - You can report issues or suggest new features on our 71 | [Discord server](https://discord.gg/WRUWENZnzQ) or using 72 | [Github Issues](https://github.com/rustic-rs/rustic_server/issues/new/choose)! 73 | 74 | Do you know how to code or got an idea for an improvement? Don't keep it to 75 | yourself! 76 | 77 | - Contribute fixes or new features via a pull requests! 78 | 79 | Please make sure, that you read the 80 | [contribution guide](https://rustic.cli.rs/docs/contributing-to-rustic.html). 81 | 82 | ## Minimum Rust version policy 83 | 84 | This crate's minimum supported `rustc` version is `1.70.0`. 85 | 86 | The current policy is that the minimum Rust version required to use this crate 87 | can be increased in minor version updates. For example, if `crate 1.0` requires 88 | Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust 89 | 1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum 90 | version of Rust. 91 | 92 | In general, this crate will be conservative with respect to the minimum 93 | supported version of Rust. 94 | 95 | # License 96 | 97 | `rustic-server` is open-sourced software licensed under the 98 | [GNU Affero General Public License v3.0 or later](./LICENSE). 99 | -------------------------------------------------------------------------------- /USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | You can start the server with the following command: 4 | 5 | ```console 6 | rustic-server serve 7 | ``` 8 | 9 | ## Defaults 10 | 11 | ### Storage 12 | 13 | By default the server persists backup data in the OS temporary directory 14 | (`/tmp/rustic` on Linux/BSD and others, in `%TEMP%\\rustic` in Windows, etc). 15 | 16 | **If `rustic-server` is launched using the default path, all backups will be 17 | lost**. To start the server with a custom persistence directory and with 18 | authentication disabled: 19 | 20 | ```sh 21 | rustic-server --path /user/home/backup --no-auth 22 | ``` 23 | 24 | `rustic-server` uses exactly the same directory structure as local backend, so 25 | you should be able to access it both locally and via HTTP, even simultaneously. 26 | 27 | ### Authentication (Basic) 28 | 29 | To authenticate users (for access to the `rustic-server`), the server supports 30 | using a `.htpasswd` file to specify users. By default, the server looks for this 31 | file at the root of the persistence directory, but this can be changed using the 32 | `--htpasswd-file` option. You can create such a file by executing the following 33 | command (note that you need the `htpasswd` program from Apache's http-tools). In 34 | order to append new user to the file, just omit the `-c` argument. Only bcrypt 35 | and SHA encryption methods are supported, so use -B (very secure) or -s 36 | (insecure by today's standards) when adding/changing passwords. 37 | 38 | ```sh 39 | htpasswd -B -c .htpasswd username 40 | ``` 41 | 42 | If you want to disable authentication, you must add the `--no-auth` flag. If 43 | this flag is not specified and the `.htpasswd` cannot be opened, `rustic-server` 44 | will refuse to start. 45 | 46 | ### Transport Layer Security (TLS) 47 | 48 | By default the server uses HTTP protocol. This is not very secure since with 49 | Basic Authentication, user name and passwords will be sent in clear text in 50 | every request. In order to enable TLS support just add the `--tls` argument and 51 | specify private and public keys by `--tls-cert` and `--tls-key`. 52 | 53 | Signed certificate is normally required by `restic` and `rustic`, but if you 54 | just want to test the feature you can generate password-less unsigned keys with 55 | the following command: 56 | 57 | ```sh 58 | openssl req -newkey rsa:2048 -nodes -x509 -keyout private_key -out public_key -days 365 -addext "subjectAltName = IP:127.0.0.1,DNS:yourdomain.com" 59 | ``` 60 | 61 | Omit the `IP:127.0.0.1` if you don't need your server be accessed via SSH 62 | Tunnels. No need to change default values in the openssl dialog, hitting enter 63 | every time is sufficient. 64 | 65 | To access this server via `restic` use `--cacert public_key`, meaning with a 66 | self-signed certificate you have to distribute your `public_key` file to every 67 | `restic` client. 68 | 69 | ### Access Control List (ACL) 70 | 71 | To prevent your users from accessing each others' repositories, you may use the 72 | `--private-repos` flag in combination with an ACL file. 73 | 74 | This server supports `ACL`s to restrict access to repositories. The ACL file is 75 | formatted in TOML and can be specified using the `--acl-path` option. More 76 | information about the ACL file format can be found in the `acl.toml` file in the 77 | `config` directory. If the ACL file is not specified, the server will allow all 78 | users to access all repositories. 79 | 80 | For example, user "foo" using the repository URLs 81 | `rest:https://foo:pass@host:8000/foo` or `rest:https://foo:pass@host:8000/foo/` 82 | would be granted access, but the same user using repository URLs 83 | `rest:https://foo:pass@host:8000/` or `rest:https://foo:pass@host:8000/foobar/` 84 | would be denied access. Users can also create their own sub repositories, like 85 | `/foo/bar/`. 86 | 87 | ## Append-Only Mode 88 | 89 | The `--append-only` mode allows creation of new backups but prevents deletion 90 | and modification of existing backups. This can be useful when backing up systems 91 | that have a potential of being hacked. 92 | 93 | ## Credits 94 | 95 | This project is based on the 96 | [rest-server](https://github.com/restic/rest-server) project by 97 | [restic](https://restic.net). This document is based on the 98 | [README.md](https://github.com/restic/rest-server/blob/e35c6e39d9c8d658338e1d9a0e4a57a50e151957/README.md) 99 | of the rest-server project. 100 | -------------------------------------------------------------------------------- /build-dependencies.just: -------------------------------------------------------------------------------- 1 | ### DEFAULT ### 2 | 3 | # Install dependencies for the default feature on x86_64-unknown-linux-musl 4 | install-default-x86_64-unknown-linux-musl: 5 | sudo apt-get update 6 | sudo apt-get install -y musl-tools 7 | 8 | # Install dependencies for the default feature on aarch64-unknown-linux-musl 9 | install-default-aarch64-unknown-linux-musl: 10 | sudo apt-get update 11 | sudo apt-get install -y musl-tools 12 | 13 | # Install dependencies for the default feature on i686-unknown-linux-gnu 14 | install-default-i686-unknown-linux-gnu: 15 | sudo apt-get update 16 | sudo apt-get install -y gcc-multilib-i686-linux-gnu gcc-i686-linux-gnu 17 | -------------------------------------------------------------------------------- /cliff.toml: -------------------------------------------------------------------------------- 1 | # git-cliff ~ default configuration file 2 | # https://git-cliff.org/docs/configuration 3 | # 4 | # Lines starting with "#" are comments. 5 | # Configuration options are organized into tables and keys. 6 | # See documentation for more information on available options. 7 | 8 | [changelog] 9 | # changelog header 10 | header = """ 11 | # Changelog\n 12 | All notable changes to this project will be documented in this file.\n 13 | """ 14 | # template for the changelog body 15 | # https://tera.netlify.app/docs 16 | body = """ 17 | {% if version %}\ 18 | ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} 19 | {% else %}\ 20 | ## [unreleased] 21 | {% endif %}\ 22 | {% for group, commits in commits | group_by(attribute="group") %} 23 | ### {{ group | upper_first }} 24 | {% for commit in commits %} 25 | - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\ 26 | {% endfor %} 27 | {% endfor %}\n 28 | """ 29 | # remove the leading and trailing whitespace from the template 30 | trim = true 31 | # changelog footer 32 | footer = """ 33 | 34 | """ 35 | # postprocessors 36 | postprocessors = [ 37 | { pattern = '
2 |
3 |