Linuxで特定のポートを外部に開放する方法

# このドキュメントでできること

- 特定のポートを外部ネットワークに解放する
- 内部で開いているポートとは別のポート番号で外部ネットワークに開放する

# 緒言

WebサーバーやDBサーバーなどがインストールされたマシンに外部ネットワークからアクセスできるようにするためには、プログラムが開いているポートを外部に開放する必要があります。

ところが、通常Linuxではファイアウォールが動いており、外部ネットワークからのアクセスが遮断されています。
従って、ファイアウォールの設定を変更し、特定のポートを外部に開放する必要があります。

また、このとき、内部で開いているポートとは違うポートで外部に開放したい場合もあります。

例えば、一般ユーザー権限で動いているプログラムを1024番以下のポートで外部に開放したい場合です。
1024番以下のポートはrootでしか開けないため、一般ユーザーがこのポートを使って外部にサービスを提供することはできません。

この問題を解決する方法はいくつかありますが、一番簡単なのは`ポートフォワード`を使うことです。

この文章では、このような2つのケースに対応した、設定方法について解説していきます。

※なお、実行するコマンドは全てrootユーザーで実行します。


# 事前確認

### クラウド環境の場合

最初に、クラウド環境の場合は、コンテナの設定でポートが解放されているか確認してください。

そもそもここが解放されていないと、マシン側でいくら設定してもアクセスできるようになりません。
（筆者もハマりましたwww）

例えば、Microsoft Azureの場合は以下のような画面で設定ができます。

<img alt="addport.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409484/a5676e36-0cd0-a76c-c213-8a2311a88d83.png" width="400">



### FirewallDが動いているか

FirewallDが動いていることを確認します。

もちろん、ファイアウォールを動かさなければ何のセキュリティの設定もされないので、ポートは開放されているわけですがwww

```
# service firewalld status
Redirecting to /bin/systemctl status firewalld.service
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:firewalld(1)
```

Activeのところがdeadになっている場合は起動します。

```
# service firewalld start
または
# systemctl start firewalld.service
```


なお、ポートフォワードは`iptables`を使っても行えます。
この場合はFirewallDは必要ありません。

iptablesを使った方法については最後に記述しました。




# 内部と同じポートを解放する方法
内部ポートと外部ポートが同じ場合は、firewall-cmdを使って、特定のポートを解放するだけです

```
# firewall-cmd --add-port 1080/tcp
```

設定を確認します

```
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports: 1080/tcp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
```

これで外部からアクセスできるようになりました。

この設定は一時的なもので、マシンをシャットダウンするとクリアされます。

設置を恒久的にするには以下のように`--permanent`オプションをつけてもう一度コマンドを打ちます。

```
# firewall-cmd --add-port=1080/tcp --permanent
```

`--permanent`を指定した場合は、逆に起動中のFireWallDには反映されないんですね。もし二度打ちが面倒だったら、最初に`--permanent`を指定して以下のようにリロードするという方法もあります。

```
# firewall-cmd --reload
```

ま、回数的に二度打ちには変わりはありませんがwww

設定を戻すには以下のように`--remove-port`を使います

```
# firewall-cmd --remove-port=1080/tcp --permanent
# firewall-cmd --remove-port=1080/tcp 
```


# 内部とは異なるポートを解放する方法

例えば、内部で1080番ポートで開いているが、外からは80番でアクセスさせたい場合、以下のようにポートフォワードの設定をします

```
# firewall-cmd --add-forward-port=port=80:proto=tcp:toport=1080
```

設定を確認します。

```
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports: port=80:proto=tcp:toport=1080:toaddr=
  source-ports:
  icmp-blocks:
  rich rules:
```

これで、外部からアクセスできるようになりました。

先ほと同様、変更を恒久的にするには`--permanent`を指定してもう一度実行します

```
# firewall-cmd --add-forward-port=port=80:proto=tcp:toport=1080 --permanent
```

設定を元に戻す場合は`--remove-forward-port`を使います

```
# firewall-cmd --remove-forward-port=port=80:proto=tcp:toport=1080 --permanent
# firewall-cmd --remove-forward-port=port=80:proto=tcp:toport=1080 
```



# (おまけ)iptablesで設定する方法

FirewallDを起動せずにポートフォワードを使用する場合は、`iptables`を使います。

```
# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 1080
```

ただ、FirewallDを動かしたときこの設定がどうなるかよくわからないので、お勧めはしませんがw



# 結言

このドキュメントでは、内部のポートを外部に開放する方法について2種類説明しました

- 内部のポートをそのまま開放する方法
- ポート番号を変えて開放する方法

Enjoy!