SORACOM Harvest Files内にDebianのリポジトリを構築する

# はじめに

以前の記事[「最強のセキュリティを誇るSORACOM Private Gardenが実用に耐えるかを検証する」](https://qiita.com/1stship/items/47afae52a5fd7ec53315)にて「aptなどのパッケージ管理ツールからのアップデートが出来ないのは難点ですが」と書きましたが、よく考えるとSORACOM Beam使えば簡単に対応できるな、ということに気付きましたので、試してまとめようと思ったのですが、、うまく行かなかったのでSORACOM Harvest Filesにリポジトリを作成する方法にしました。

試行錯誤をそのまま書いているので長いです。最終的な方法だけ知りたい場合は[こちら](#使うコマンド最終版)

# Private Gardenとは

ソラコムサービス以外への通信を遮断することで、IoTに必要な機能はそのままに高いセキュリティを実現する機能です。

詳しい説明はこちらの公式資料
https://dev.soracom.io/jp/docs/private_garden/

および過去のブログ
https://qiita.com/1stship/items/47afae52a5fd7ec53315

をご覧ください。

# やりたいこと

デバイスから意図しないサーバにアクセスしてしまうことを完全に防ぎつつ、通常のアップデート作業も実施できるようにしたい。

SORACOM Private Gardenのネットワーク下で、aptによるパッケージインストールができるようにすることを目標とします。

# SORACOM Beamでの対応を試す

aptにおいては、
/etc/apt/sources.list
に指定されたリポジトリにHTTPでGETしてパッケージリストおよびパッケージそのものを持ってきます。

```bash
pi@raspberrypi:~ $ sudo cat /etc/apt/sources.list
deb http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
```

となっていますので、
http://beam.soracom.io:18080
に対するアクセスが、
http://raspbian.raspberrypi.org
に転送されるようにすれば良さそうです。

## 準備

/etc/apt/sources.listを以下のように変更します。

```bash
deb http://beam.soracom.io:18080/raspbian/ stretch main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
```

続いてSORACOM BeamのWebサイト転送設定を以下のように設定します。

![スクリーンショット 2020-01-03 17.54.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/0ac7ed64-bc15-0556-8e6d-4c25538793f5.png)

（実は/etc/apt/sources.list.d/raspi.listにもリポジトリ設定があるのですが、そちらはとりあえずコメントアウトしておきます）

## 実行

apt-get updateしてみます。

```bash
pi@raspberrypi:~ $ sudo apt-get update
Get:1 http://beam.soracom.io:18080/raspbian stretch InRelease [15.0 kB]
Get:2 http://beam.soracom.io:18080/raspbian stretch/main armhf Packages [11.7 MB]
Err:2 http://beam.soracom.io:18080/raspbian stretch/main armhf Packages                            
  Hash Sum mismatch
  Hashes of expected file:
   - Filesize:11662628 [weak]
   - SHA256:880d0d8c1f0d85daf060369661c1a2363d6774cf300bd1f3340d88622a6b5dc9
   - SHA1:28677c88caf9db67c653dee3ba580881b4bd6fe0 [weak]
   - MD5Sum:21ef3b718a219ff9cfc825efaa680c8c [weak]
  Hashes of received file:
   - SHA256:26e95f44a5bfb99e925301be6e2cff95a4284856c28d8d8e35f97f068135211f
   - SHA1:0fdb9efd83b73e608283be42008e4cc351968f8d [weak]
   - MD5Sum:0c45dce31528d0d642aaf5430ded9620 [weak]
   - Filesize:9043057 [weak]
  Last modification reported: Sat, 28 Dec 2019 04:32:44 +0000
  Release file created at: Fri, 03 Jan 2020 04:34:24 +0000
Get:3 http://beam.soracom.io:18080/raspbian stretch/contrib armhf Packages [56.9 kB]               
Get:4 http://beam.soracom.io:18080/raspbian stretch/non-free armhf Packages [95.5 kB]              
Get:5 http://beam.soracom.io:18080/raspbian stretch/rpi armhf Packages [1,360 B]                   
Fetched 9,049 kB in 6min 31s (23.1 kB/s)                                                           
Reading package lists... Done
E: Failed to fetch http://beam.soracom.io:18080/raspbian/dists/stretch/main/binary-armhf/Packages.xz  Hash Sum mismatch
   Hashes of expected file:
    - Filesize:11662628 [weak]
    - SHA256:880d0d8c1f0d85daf060369661c1a2363d6774cf300bd1f3340d88622a6b5dc9
    - SHA1:28677c88caf9db67c653dee3ba580881b4bd6fe0 [weak]
    - MD5Sum:21ef3b718a219ff9cfc825efaa680c8c [weak]
   Hashes of received file:
    - SHA256:26e95f44a5bfb99e925301be6e2cff95a4284856c28d8d8e35f97f068135211f
    - SHA1:0fdb9efd83b73e608283be42008e4cc351968f8d [weak]
    - MD5Sum:0c45dce31528d0d642aaf5430ded9620 [weak]
    - Filesize:9043057 [weak]
   Last modification reported: Sat, 28 Dec 2019 04:32:44 +0000
   Release file created at: Fri, 03 Jan 2020 04:34:24 +0000
E: Some index files failed to download. They have been ignored, or old ones used instead.
```

あれ？なんかエラーが出ていますね。。main/binary-armhf/Packages.xzのハッシュが合わない、というよりファイルサイズが合わないようです。ダウンロードに失敗していると考えられます。

アクセス自体はできていますが、ダウンロード速度が想定より遅い気がする。s1.fast(2Mbps)だから250kB/sまでは出て良いはずなのに、23.1kB/sしか出ていない。

試しにこのPackages.xzだけwgetでダウンロードしてみます。

```bash
pi@raspberrypi:~ $ wget http://beam.soracom.io:18080/raspbian/dists/stretch/main/binary-armhf/Packages.xz
--2020-01-03 08:17:45--  http://beam.soracom.io:18080/raspbian/dists/stretch/main/binary-armhf/Packages.xz
Resolving beam.soracom.io (beam.soracom.io)... 100.127.127.100
Connecting to beam.soracom.io (beam.soracom.io)|100.127.127.100|:18080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11662628 (11M) [application/x-xz]
Saving to: ‘Packages.xz’

Packages.xz               81%[===========================>       ]   9.01M  19.3KB/s    in 9m 37s  

2020-01-03 08:27:26 (16.0 KB/s) - Connection closed at byte 9447487. Retrying.

--2020-01-03 08:27:27--  (try: 2)  http://beam.soracom.io:18080/raspbian/dists/stretch/main/binary-armhf/Packages.xz
Connecting to beam.soracom.io (beam.soracom.io)|100.127.127.100|:18080... connected.
HTTP request sent, awaiting response... 206 Partial Content
Length: 11662628 (11M), 2215141 (2.1M) remaining [application/x-xz]
Saving to: ‘Packages.xz’

Packages.xz              100%[++++++++++++++++++++++++++++======>]  11.12M  22.4KB/s    in 99s     

2020-01-03 08:29:07 (21.8 KB/s) - ‘Packages.xz’ saved [11662628/11662628]
```

9m37sでいったん接続が切られ、その後再接続で続きを取得してダウンロードしたようですね。この一度切られるところでapt-getのダウンロードは終了してしまったと思われます。

ためしにPrivate Gardenではない環境でraspbian.raspberrypi.orgに対して実行すると、

```bash
pi@raspberrypi:~ $ sudo apt-get update
Get:1 http://raspbian.raspberrypi.org/raspbian stretch InRelease [15.0 kB]
Get:2 http://raspbian.raspberrypi.org/raspbian stretch/main armhf Packages [11.7 MB]
Get:3 http://raspbian.raspberrypi.org/raspbian stretch/contrib armhf Packages [56.9 kB]            
Get:4 http://raspbian.raspberrypi.org/raspbian stretch/non-free armhf Packages [95.5 kB]           
Get:5 http://raspbian.raspberrypi.org/raspbian stretch/rpi armhf Packages [1,360 B]                
Fetched 11.8 MB in 1min 2s (189 kB/s)                                                              
Reading package lists... Done
```

189 kB/sで普通にapt-get updateは成功しました。ということは、

「SORACOM Beamを通すとダウンロードが遅くなる」
「その結果いったん通信が途切れる」
「apt-getは分割ダウンロードに対応していない」

という現象に思えます。原因は不明です。どれか１つでもOKであればいけそうなんですが、残念。

# SORACOM Harvest Filesをリポジトリとして使用する

SORACOM Beamでは残念ながらうまく行かなかったため、SORACOM Harvest Filesにパッケージリストとパッケージ本体を置き、そこからダウンロードさせる方法を考えます。

Beamでの転送設定に比べ準備がやや大変ですが、パッケージリストやパッケージ本体が勝手に変わらないというメリットがありますので、実使用上はこちらの方が良いかも知れません。

## パッケージリストの作成

まずダウンロードすべきパッケージ群を用意します。
以下はRaspberry Pi上で、Private Gardenではない通常のSORACOM Airネットワーク内で、raspbian.raspberrypi.orgを参照する設定で実施しています。

apt-getでインストールされるパッケージは/var/cache/apt/archivesディレクトリに入ります。インターネットに接続している状態でまずここにダウンロードすべきdebパッケージファイルをダウンロードします。

インストールさせるパッケージがapache2だとすると、以下のコマンドで依存するパッケージファイルをダウンロードできます。（ただし実行時点ですでにインストールされているパッケージはダウンロードされないので、ベースになる状態で実行するのがよいでしょう）

```bash
pi@raspberrypi:~ $ sudo apt-get clean
pi@raspberrypi:~ $ sudo apt-get --download-only -y install apache2
```

これで必要なパッケージは/var/cache/apt/archives/に入りましたので、適当なディレクトリにそれを移動させます。(所有者がrootになってしまっているので所有者は一般ユーザーにします)

```bash
pi@raspberrypi:~ $ mkdir apt
pi@raspberrypi:~ $ cp /var/cache/apt/archives/*.deb apt/
pi@raspberrypi:~ $ sudo chown pi:pi apt/*
```

次にapt-ftparchiveを使ってパッケージリストなどを作成します。(ftparchiveという名前ですが、もちろんhttpで配布できます)

パッケージリスト作成に先立ち、[GPG](https://ja.wikipedia.org/wiki/GNU_Privacy_Guard)のキーペアを作成する必要があります。(なくてもいいのですが、ないとパッケージリスト取得の際にワーニングが出ます)

```bash
gpg --gen-key
```

名前、メールアドレスを入力し、ランダムな入力でエントロピーが十分貯まると(エントロピーはキーボード、マウス入力などで貯まりますが、[Rng-tools](https://wiki.archlinux.jp/index.php/Rng-tools)を使うと早いです)

GPGのキーペアが作成できたら、パッケージリストを作成します。
以下のURLの記事を参考にさせていただきました。
https://linux.just4fun.biz/?Ubuntu/ネットワークインストール用の独自のパッケージレポジトリを作成する

```bash
pi@raspberrypi:~ $ cd apt
pi@raspberrypi:~/apt $ apt-ftparchive packages . > Packages
pi@raspberrypi:~/apt $ gzip -c9 < Packages > Packages.gz
pi@raspberrypi:~/apt $ apt-ftparchive contents . > Contents-$(dpkg --print-architecture)
pi@raspberrypi:~/apt $ gzip -c9 < Contents-$(dpkg --print-architecture) > Contents-$(dpkg --print-architecture).gz
pi@raspberrypi:~/apt $ apt-ftparchive release . > Release
pi@raspberrypi:~/apt $ gpg --sign -b -a -o Release.gpg Release
pi@raspberrypi:~/apt $ gpg --export > raspi.gpg
```

これで配布すべきパッケージのリストはできました。最後に作成したのはGPGの公開鍵で、リポジトリを使う際にあらかじめデバイスにインストールしておく必要があるものです。

作業しているRaspberry PiからAPIでアップロードします。（もちろんコンソールからアップロードしてもよいのですが、コンソールだと複数ファイルまとめて選択できず手間がかかりそうだったので）ルートに置いてもよいのですが、他のファイルと混ざると後々面倒なので、raspi以下のパスに置くようにしています。

```bash
for file in $(ls); do curl -X PUT --data-binary @$file -H 'content-type:application/octet-stream' http://harvest-files.soracom.io/raspi/$file; done
```

結果このようにファイルがアップロードされました。

![スクリーンショット 2020-01-04 0.39.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/b4791963-91ce-c2c6-28cd-8ffb98e7d1bf.png)

## トライ1

まず再度Private Gardenに入れます。(セッションを切るのを忘れないように)

ついでGPGの公開鍵をインストールします。

```bash
pi@raspberrypi:~/apt $ curl http://harvest-files.soracom.io/raspi/raspi.gpg | sudo apt-key add -
```

/etc/apt/sources.list.d/harvest.listを作成し、harvest-files.soracom.io/raspiの/からパッケージをインストールするように指定します。（/etc/apt/sources.listと/etc/apt/sources.list.d/raspi.listのリポジトリはコメントアウトしておきます）

```bash
pi@raspberrypi:~/apt $ cat /etc/apt/sources.list.d/harvest.list 
deb http://harvest-files.soracom.io/raspi /
```

apt-get updateでReleaseとPackagesを読み出します。

```bash
pi@raspberrypi:~/apt $ sudo apt-get update
Ign:1 http://harvest-files.soracom.io/raspi  InRelease      
Get:2 http://harvest-files.soracom.io/raspi  Release [2,016 B]
Get:3 http://harvest-files.soracom.io/raspi  Release.gpg [659 B]
Get:4 http://harvest-files.soracom.io/raspi  Packages [3,923 B]
Fetched 6,598 B in 4s (1,384 B/s) 
Reading package lists... Done
```

うまくいきましたね。ではインストールします。

```bash
pi@raspberrypi:~/apt $ sudo apt-get -y install apache2
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.2-0
Suggested packages:
  www-browser apache2-doc apache2-suexec-pristine | apache2-suexec-custom
The following NEW packages will be installed:
  apache2 apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.2-0
0 upgraded, 9 newly installed, 0 to remove and 0 not upgraded.
Need to get 1,932 kB of archives.
After this operation, 6,206 kB of additional disk space will be used.
Err:1 http://harvest-files.soracom.io/raspi  libapr1 1.5.2-5
  400  Bad Request
Err:2 http://harvest-files.soracom.io/raspi  libaprutil1 1.5.4-3
  400  Bad Request
Err:3 http://harvest-files.soracom.io/raspi  libaprutil1-dbd-sqlite3 1.5.4-3
  400  Bad Request
Err:4 http://harvest-files.soracom.io/raspi  libaprutil1-ldap 1.5.4-3
  400  Bad Request
Err:5 http://harvest-files.soracom.io/raspi  liblua5.2-0 5.2.4-1.1
  400  Bad Request
Err:6 http://harvest-files.soracom.io/raspi  apache2-bin 2.4.25-3+deb9u9
  400  Bad Request
Err:7 http://harvest-files.soracom.io/raspi  apache2-utils 2.4.25-3+deb9u9
  400  Bad Request
Err:8 http://harvest-files.soracom.io/raspi  apache2-data 2.4.25-3+deb9u9
  400  Bad Request
Err:9 http://harvest-files.soracom.io/raspi  apache2 2.4.25-3+deb9u9
  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./libapr1_1.5.2-5_armhf.deb  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./libaprutil1_1.5.4-3_armhf.deb  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./libaprutil1-dbd-sqlite3_1.5.4-3_armhf.deb  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./libaprutil1-ldap_1.5.4-3_armhf.deb  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./liblua5.2-0_5.2.4-1.1_armhf.deb  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./apache2-bin_2.4.25-3+deb9u9_armhf.deb  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./apache2-utils_2.4.25-3+deb9u9_armhf.deb  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./apache2-data_2.4.25-3+deb9u9_all.deb  400  Bad Request
E: Failed to fetch http://harvest-files.soracom.io/raspi/./apache2_2.4.25-3+deb9u9_armhf.deb  400  Bad Request
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
```

あれ？なにか派手に失敗してしまいました。

## トライ1失敗原因: ファイルパスに.が入っているとダメ

何が問題なのかというと

http://harvest-files.soracom.io/raspi/./libapr1_1.5.2-5_armhf.deb

などの取得が**400 Bad Request**になっています。
どうも、 . のようなファイルがあるとBad Requestになるようで、おそらく[ディレクトリトラバーサル攻撃](https://ja.wikipedia.org/wiki/ディレクトリトラバーサル)対策かと思われます。

先ほどPackagesを生成した時、カレントディレクトリにあるパッケージを参照したため、このようなURLになってしまったのでしょう。たとえばPackagesには

`Filename: ./apache2_2.4.25-3+deb9u9_armhf.deb`

という記載があり、この「./」の部分を取り除くとうまく行きそうですが、ツールでの生成物にうかつに手を出すとろくなことにならなそうなので、ディレクトリ構成を変えることで対応します。

## トライ2準備

aptディレクトリ直下にパッケージを直接置くのではなく、pkgディレクトリを作成し、その下にパッケージ群を置いて、aptディレクトリ内で再度パッケージリストを生成します。この時、pkgを指定するよう変更するのを忘れないようにします。

```bash
pi@raspberrypi:~/apt $ apt-ftparchive packages pkg > Packages
pi@raspberrypi:~/apt $ gzip -c9 < Packages > Packages.gz
pi@raspberrypi:~/apt $ apt-ftparchive contents . > Contents-$(dpkg --print-architecture)
pi@raspberrypi:~/apt $ gzip -c9 < Contents-$(dpkg --print-architecture) > Contents-$(dpkg --print-architecture).gz
pi@raspberrypi:~/apt $ apt-ftparchive release . > Release
pi@raspberrypi:~/apt $ gpg --sign -b -a -o Release.gpg Release
pi@raspberrypi:~/apt $ gpg --export > raspi.gpg
```

aptディレクトリはこのような構成になります。

```bash
├── Contents-armhf
├── Contents-armhf.gz
├── Packages
├── Packages.gz
├── pkg
│   ├── apache2_2.4.25-3+deb9u9_armhf.deb
│   ├── apache2-bin_2.4.25-3+deb9u9_armhf.deb
│   ├── apache2-data_2.4.25-3+deb9u9_all.deb
│   ├── apache2-utils_2.4.25-3+deb9u9_armhf.deb
│   ├── libapr1_1.5.2-5_armhf.deb
│   ├── libaprutil1_1.5.4-3_armhf.deb
│   ├── libaprutil1-dbd-sqlite3_1.5.4-3_armhf.deb
│   ├── libaprutil1-ldap_1.5.4-3_armhf.deb
│   └── liblua5.2-0_5.2.4-1.1_armhf.deb
├── raspi.gpg
├── Release
└── Release.gpg
```

一度Harvest Filesのファイルを削除して、再度アップロードします。ワンライナーはサブディレクトリ内を含めるように改変しました。

```bash
for file in $(find . -type f | cut -c3-); do curl -X PUT --data-binary @$file -H 'content-type:application/octet-stream' http://harvest-files.soracom.io/raspi/$file; done
```

## トライ2実行

再度apt-get update、update-get installを実行します。(apt-get updateの記載は省略)

```bash
pi@raspberrypi:~/apt $ sudo apt-get -y install apache2
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.2-0
Suggested packages:
  www-browser apache2-doc apache2-suexec-pristine | apache2-suexec-custom
The following NEW packages will be installed:
  apache2 apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.2-0
0 upgraded, 9 newly installed, 0 to remove and 0 not upgraded.
Need to get 1,932 kB of archives.
After this operation, 6,206 kB of additional disk space will be used.
Get:1 http://harvest-files.soracom.io/raspi  libapr1 1.5.2-5 [79.8 kB]
Get:2 http://harvest-files.soracom.io/raspi  libaprutil1 1.5.4-3 [75.9 kB]                                                                                                     
Get:3 http://harvest-files.soracom.io/raspi  libaprutil1-dbd-sqlite3 1.5.4-3 [17.9 kB]                                                                                         
Get:4 http://harvest-files.soracom.io/raspi  libaprutil1-ldap 1.5.4-3 [16.9 kB]                                                                                                
Get:5 http://harvest-files.soracom.io/raspi  liblua5.2-0 5.2.4-1.1 [82.8 kB]                                                                                                   
Err:6 http://harvest-files.soracom.io/raspi  apache2-bin 2.4.25-3+deb9u9                                                                                                       
  404  Not Found
Err:7 http://harvest-files.soracom.io/raspi  apache2-utils 2.4.25-3+deb9u9                                                                                                     
  404  Not Found
Err:8 http://harvest-files.soracom.io/raspi  apache2-data 2.4.25-3+deb9u9                                                                                                      
  404  Not Found
Err:9 http://harvest-files.soracom.io/raspi  apache2 2.4.25-3+deb9u9                                                                                                           
  404  Not Found
Fetched 273 kB in 13s (20.5 kB/s)                                                                                                                                              
E: Failed to fetch http://harvest-files.soracom.io/raspi/pkg/apache2-bin_2.4.25-3+deb9u9_armhf.deb  404  Not Found
E: Failed to fetch http://harvest-files.soracom.io/raspi/pkg/apache2-utils_2.4.25-3+deb9u9_armhf.deb  404  Not Found
E: Failed to fetch http://harvest-files.soracom.io/raspi/pkg/apache2-data_2.4.25-3+deb9u9_all.deb  404  Not Found
E: Failed to fetch http://harvest-files.soracom.io/raspi/pkg/apache2_2.4.25-3+deb9u9_armhf.deb  404  Not Found
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
```

また失敗した。。今度は何だ？404 Not Found? ファイルがアップロードされていることは確認しています。それでもNot Foundが出る。

## トライ2失敗原因: ファイル名に+が入っているとダメ

失敗したのはファイル名に「+」が入るものです。どうも、apt-getはURLに+などのURLセーフでない文字が入ると自動的にURLエンコードするけど、Harvest Files側はデコードしてキーの一致を見ているわけでは無いため、Not Foundになってしまっているようです。

例えば、
`apache2-bin_2.4.25-3+deb9u9_armhf.deb`
をリクエストする時には
`apache2-bin_2.4.25-3%2bdeb9u9_armhf.deb`
としてリクエストしている。まあそりゃそうかという動作ですが、Harvest Filesとは相性が悪い模様。apt-getでURLエンコードをしないオプションは見つけられず。

## トライ3準備

仕方ないので、Harvest Filesにアップロードする際、以下の~~雑な~~コマンドでファイル名の+を%2bに変換して送信することにしました。

```bash
for file in $(find . -type f | cut -c3-); do curl -X PUT --data-binary @$file -H 'content-type:application/octet-stream' http://harvest-files.soracom.io/raspi/$(echo $file | sed s/+/%2b/ ); done
```

ちなみにさっきのファイルを消さずにこれをしたところ、Harvest Files上ではこんな感じになりました。

![スクリーンショット 2020-01-04 12.43.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/b06cef02-5b6f-5799-f682-fe84c624e679.png)

+が入っているファイルは、同じファイル名のファイルが別物として扱われていることがわかります。内部的にはファイル名が+になっているものと%2bになっているものにが存在しているが、表示する時にはURLエンコードをデコードして表示しているようですね。

## トライ3実行

今度こそ。。どうだ！

```bash
pi@raspberrypi:~/apt $ sudo apt-get -y install apache2
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.2-0
Suggested packages:
  www-browser apache2-doc apache2-suexec-pristine | apache2-suexec-custom
The following NEW packages will be installed:
  apache2 apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.2-0
0 upgraded, 9 newly installed, 0 to remove and 0 not upgraded.
Need to get 1,659 kB/1,932 kB of archives.
After this operation, 6,206 kB of additional disk space will be used.
Get:1 http://harvest-files.soracom.io/raspi  apache2-bin 2.4.25-3+deb9u9 [1,041 kB]
Get:2 http://harvest-files.soracom.io/raspi  apache2-utils 2.4.25-3+deb9u9 [219 kB]                                                                                            
Get:3 http://harvest-files.soracom.io/raspi  apache2-data 2.4.25-3+deb9u9 [162 kB]                                                                                             
Get:4 http://harvest-files.soracom.io/raspi  apache2 2.4.25-3+deb9u9 [237 kB]                                                                                                  
Fetched 1,659 kB in 1min 42s (16.2 kB/s)                                                                                                                                       
Selecting previously unselected package libapr1:armhf.
(Reading database ... 60956 files and directories currently installed.)
Preparing to unpack .../0-libapr1_1.5.2-5_armhf.deb ...
Unpacking libapr1:armhf (1.5.2-5) ...
Selecting previously unselected package libaprutil1:armhf.
Preparing to unpack .../1-libaprutil1_1.5.4-3_armhf.deb ...
Unpacking libaprutil1:armhf (1.5.4-3) ...
Selecting previously unselected package libaprutil1-dbd-sqlite3:armhf.
Preparing to unpack .../2-libaprutil1-dbd-sqlite3_1.5.4-3_armhf.deb ...
Unpacking libaprutil1-dbd-sqlite3:armhf (1.5.4-3) ...
Selecting previously unselected package libaprutil1-ldap:armhf.
Preparing to unpack .../3-libaprutil1-ldap_1.5.4-3_armhf.deb ...
Unpacking libaprutil1-ldap:armhf (1.5.4-3) ...
Selecting previously unselected package liblua5.2-0:armhf.
Preparing to unpack .../4-liblua5.2-0_5.2.4-1.1_armhf.deb ...
Unpacking liblua5.2-0:armhf (5.2.4-1.1) ...
Selecting previously unselected package apache2-bin.
Preparing to unpack .../5-apache2-bin_2.4.25-3+deb9u9_armhf.deb ...
Unpacking apache2-bin (2.4.25-3+deb9u9) ...
Selecting previously unselected package apache2-utils.
Preparing to unpack .../6-apache2-utils_2.4.25-3+deb9u9_armhf.deb ...
Unpacking apache2-utils (2.4.25-3+deb9u9) ...
Selecting previously unselected package apache2-data.
Preparing to unpack .../7-apache2-data_2.4.25-3+deb9u9_all.deb ...
Unpacking apache2-data (2.4.25-3+deb9u9) ...
Preparing to unpack .../8-apache2_2.4.25-3+deb9u9_armhf.deb ...
Unpacking apache2 (2.4.25-3+deb9u9) ...
Setting up libapr1:armhf (1.5.2-5) ...
Setting up apache2-data (2.4.25-3+deb9u9) ...
Processing triggers for libc-bin (2.24-11+deb9u3) ...
Setting up libaprutil1:armhf (1.5.4-3) ...
Processing triggers for systemd (232-25+deb9u6) ...
Processing triggers for man-db (2.7.6.1-2) ...
Setting up liblua5.2-0:armhf (5.2.4-1.1) ...
Setting up libaprutil1-ldap:armhf (1.5.4-3) ...
Setting up libaprutil1-dbd-sqlite3:armhf (1.5.4-3) ...
Setting up apache2-utils (2.4.25-3+deb9u9) ...
Setting up apache2-bin (2.4.25-3+deb9u9) ...
Setting up apache2 (2.4.25-3+deb9u9) ...
Processing triggers for libc-bin (2.24-11+deb9u3) ...
```

ようやく成功しました！長い戦いだった。。30分で書き上がるはずだったのに。

# まとめ

SORACOM Harvest Files内にDebianのaptに対応したリポジトリを作ることができました。ややはまるところはありますが、分かっていればさほど難しくはありません。

これでパッケージ管理システムを使うデバイスでもインターネットへの経路を持たなくて良いので、よりセキュリティを向上させられますね。

なお、プライベートリポジトリでパッケージを配布することがライセンス上問題ないかはご確認ください。(Debianの普通のパッケージならほぼ問題ないとは思いますが)

以上です！

# 使うコマンド最終版

### 準備側

Raspberry Pi、インターネット環境、raspbian.raspberrypi.orgを参照する設定、piユーザー、/home/piディレクトリ内で実行する想定

```bash
sudo apt-get clean
sudo apt-get update
sudo apt-get --download-only -y install apache2 # 必要なパッケージを記載
mkdir -p apt/pkg
cp /var/cache/apt/archives/*.deb apt/pkg/
sudo chown pi:pi apt/pkg/*
cd apt
gpg --gen-key
apt-ftparchive packages pkg > Packages
gzip -c9 < Packages > Packages.gz
apt-ftparchive contents . > Contents-$(dpkg --print-architecture)
gzip -c9 < Contents-$(dpkg --print-architecture) > Contents-$(dpkg --print-architecture).gz
apt-ftparchive release . > Release
gpg --sign -b -a -o Release.gpg Release
gpg --export > raspi.gpg
for file in $(find . -type f | cut -c3-); do curl -X PUT --data-binary @$file -H 'content-type:application/octet-stream' http://harvest-files.soracom.io/raspi/$(echo $file | sed s/+/%2b/ ); done
```

### 利用側

Raspberry Pi、Private Garden環境、harvest-files.soracom.ioを参照する設定、piユーザー、/home/piディレクトリ内で実行する想定

```bash
sudo vi /etc/apt/sources.list # 全ての行をコメントアウト
sudo vi /etc/apt/sources.list.d/raspi.list # 全ての行をコメントアウト
sudo vi /etc/apt/sources.list.d/harvest.list # deb http://harvest-files.soracom.io/raspi /
curl http://harvest-files.soracom.io/raspi/raspi.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get -y install apache2 # 必要なパッケージを記載
```

# 残された謎

SORACOM Beam経由でダウンロードが遅くなるのは、何故？