複数のMiniDLNAインスタンスを起動して、アクセス制御する


# 動機

MiniDLNAには認証や認可の機能がなく、パートナーや家族に見られたくない あんなファイルやこんなファイルを隠す術がありません。そこで、

- 1つのホスト上で複数のMiniDLNAインスタンスを立ち上げて、
- それぞれのインスタンスで公開するディレクトリを変え、
- それぞれのインスタンスにアクセスできるIPアドレスやMACアドレスを制限することにより、

擬似的にアクセス制御を掛けてみることにしました。
これによって、

- このディレクトリはLAN内の全てのDLNAクライアント機器から見えるが、
- あのディレクトリは自分のスマホからしか見えない

というようなことが実現できます。

# Dockerfileを記述する

準備が楽なので Docker上でMiniDLNAを動かします。まずはそのためのDockerfileを記述します。

```:Dockerfile
FROM ubuntu:16.04
MAINTAINER flny flny@example.com

RUN apt-get update && apt-get install -y \
      minidlna

ADD start.sh /start.sh
RUN chmod +x /start.sh

EXPOSE 8200
EXPOSE 8201
EXPOSE 1900/udp

CMD /start.sh
```

```:start.sh
#!/bin/bash

service minidlna restart
/bin/bash
```

Ubuntu 16.04では ppaやbackportsなしでMiniDLNAをインストールできます。そのバージョンも1.1.5と新しくなり重大なバグが修正されているので ベースイメージは16.04としました。
また、立ち上げるインスタンスの数だけTCPのポートをEXPOSEに記述します。上記例では8200と8201の2つです。これらとは別に1900/udpも開ける必要があります。

# MiniDLNAの設定ファイルを記述する

MiniDLNAの設定ファイル(デフォルトのファイル名はminidlna.conf)をインスタンスの数だけ記述します。

```sh:minidlna.default.conf
(略)
media_dir=V,/mnt/pub/movie
(略)
# Port number for HTTP traffic (descriptions, SOAP, media transfer).
# This option is mandatory (or it must be specified on the command-line using
# "-p").
port=8200
(略)
# Name that the DLNA server presents to clients.
# Defaults to "hostname: username".
friendly_name=default
(略)
# Serial number the server reports to clients.
# Defaults to 00000000.
serial=681019830597110
uuid=0fc28baa-b6df-4002-9a7f-5994c4b85fc0
(略)
```

```sh:minidlna.rated.conf
(略)
media_dir=V,/mnt/pub/rated
(略)
# Port number for HTTP traffic (descriptions, SOAP, media transfer).
# This option is mandatory (or it must be specified on the command-line using
# "-p").
port=8201
(略)
# Name that the DLNA server presents to clients.
# Defaults to "hostname: username".
friendly_name=rated
(略)
# Serial number the server reports to clients.
# Defaults to 00000000.
serial=681019830597110
uuid=5a9884be-267d-4164-86c0-d638d98bf09b
(略)
```

色々な設定が含まれていますが、少なくとも下記のパラメータをインスタンスごとに変更します。

- ```media_dir```公開するディレクトリ
- ```port```ポート番号(DockerfileのEXPOSEに書いたポート)
- ```friendly_name```クライアントから見たサーバの名称
- ```uuid```任意のuuid

```uuid```を記述するところがこの記事唯一のポイントです。uuidの記述がないと、インスタンスを複数立ち上げてもクライアントには1つしか認識されません。uuidgenコマンドや[Online UUID Generator](https://www.uuidgenerator.net/)で uuidを生成できます。


# docker-compose.yml を記述する

インスタンスの数だけコンテナの定義を記述します。イメージはDockerfileで定義した共通のものを使用しますが、MiniDLNAの設定ファイルはコンテナごとに変えます(```volumes:```の部分)。

```yaml:docker-compose.yml
minidlna:
  image: minidlna
  container_name: dlna.default
  tty: true
  net: "host"
  volumes:
    - ./docker/minidlna/minidlna.default.conf:/etc/minidlna.conf
  command:
    "/start.sh"

rated:
  image: minidlna
  container_name: dlna.rated
  tty: true
  net: "host"
  volumes:
    - ./docker/minidlna/minidlna.rated.conf:/etc/minidlna.conf
  command:
    "/start.sh"
```

# コンテナを作成してMiniDLNAインスタンスを起動する

```docker build``` で イメージ"minidlna"を作成し、```docker-compose up```でコンテナを作成します。

```sh:
$ docker build -t minidlna <Dockerfileのあるディレクトリ>
$ docker-compose up -d minidlna rated
``` 

DLNAクライアントを起動して、DLNAサーバが2つ見えたら成功です。
![Screenshot_2016-05-27-21-18-29.png](https://qiita-image-store.s3.amazonaws.com/0/87156/211e68a6-85f2-7246-1de2-fc79feb2bf72.png)


# ファイアウォールでアクセス制御する

あとは、特定のDLNAクライアントのIPアドレスやMACアドレスをファイアウォールで弾けばOKです。IPアドレスならufwが簡単でよいですが、MACアドレスだとiptablesを直接使う必要があります。以下はufwの例です。

192.168.0.101 がホストのIPアドレス、192.168.0.201がスマホのIPアドレスだとして、rated(ポート8201)はスマホからしか見えないようにファイアウォールを設定します。

```sh:
# デフォルトを許可にする
$ sudo ufw default ALLOW
Default incoming policy changed to 'allow'
(be sure to update your rules accordingly)

# ファイアウォールを有効化する
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

# スマホから rated(ポート8201)への接続を許可する
$ sudo ufw allow from 192.168.0.201 to 192.168.0.101 port 8201
Rule added

# スマホ以外から rated(ポート8201)への接続を拒否する
$ sudo ufw deny from any to 192.168.0.101 port 8201
Rule added
```

これでスマホ以外のクライアントからはratedが見えなくなりました。

![wmp.png](https://qiita-image-store.s3.amazonaws.com/0/87156/0e090a26-0797-43c4-2e47-3f51bb7a44b6.png)


以上