Amazon LinuxのApacheにLet’s Encryptで証明書を付ける

ドメイン名を取得する

ざっくりと以下の手順。後日、別記事にする。

  1. EC2にEIPを付与
  2. ドメイン名を取得(お名前ドットコムなど)
  3. お名前ドットコム等のDNS設定でEIPを登録(AレコードでEIPを付与・CNAMEでwwwを登録)

Let's Encryptの準備

Apacheはたぶん以下のコマンドで入れた。

$ sudo yum intall httpd24 -y

Apapche 2.4にmod_ssl(SSLモジュールを入れる)。

$ sudo yum install mod24_ssl
$ sudo service httpd restart

Let's Encryptをダウンロード

$ sudo yum install git -y
$ mkdir letsencrypt
$ cd letsencrypt/
$ git clone https://github.com/certbot/certbot
$ cd certbot/

Amazon LinuxではLet's Enryptは試験状態らしい。

$ ./certbot-auto
WARNING: Amazon Linux support is very experimental at present...
if you would like to work on improving it, please ensure you have backups
and then run this script again with the --debug flag!

Let's Encryptの実行

証明書の作成
$ ./certbot-auto --debug
Is this ok [y/d/N]: y
.......
No installers are available on your OS yet; try running "letsencrypt-auto certonly" to get a cert you can install manually

$ ./certbot-auto --debug certonly

この後はTUIに従って操作。以下のようなメッセージが出る

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/XXXXXXXXXXXXXXX/fullchain.pem. Your cert will
   expire on 2016-11-05. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot-auto again. To
   non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you lose your account credentials, you can recover through
   e-mails sent to XXXXXXXXXXX@XXXXXXXXXXX.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
証明書の設定
$ cd /etc/httpd/conf.d
$ sudo vi ssl.conf
SSLCertificateFile に /etc/letsencrypt/archive/ドメイン名/fullchain.pem を設定
SSLCertificateKeyFile に /etc/letsencrypt/archive/ドメイン名/privkey.pem を設定

$ sudo service httpd restart

自分のPCでGitリポジトリサーバを動かしてソース共有する

このページに載っていることが全て

Windows: LAN内専用のGitリモートリポジトリを作る - すたらブログ

コマンド部分だけ引用する

サーバ側

$ mkdir sample.git
$ cd sample.git
$ git init --bare --shared=true
$ touch git-daemon-export-ok
$ git daemon --export-all --enable=receive-pack

既存ソースをpush

$ git remote add origin //XPS8700/sample.git
$ git push origin master
$ cd /任意の/場所
$ git clone //XPS8700/sample.git

共有フォルダの下をリポジトリにした。

C:\share\git\hoge.git
→shareを共有フォルダにする。

外部からのcloneは
git clone git://ホスト名/share/git/hoge.git

テーブルの行をテキストとしてコピーする および Drag&Dropする

リファクタリング前。
どのページを参考にしたのか忘れたので、後で追記する。

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package firstfxml.util;

import java.text.NumberFormat;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;

public class TableUtils {

    private static NumberFormat numberFormatter = NumberFormat.getNumberInstance();

    public static void installCopyPasteHandler(TableView<?> table) {
        table.setOnKeyPressed(new TableKeyEventHandler());
        table.setOnDragDetected(new TableMouseDragEventHandler2());
    }

    public static class TableMouseDragEventHandler2 implements EventHandler<MouseEvent> {

        public void handle(final MouseEvent mouseEvent) {
            if (mouseEvent.getSource() instanceof TableView) {
                dragSelection((TableView<?>) mouseEvent.getSource());
                mouseEvent.consume();

            }
        }
    }

    public static class TableKeyEventHandler implements EventHandler<KeyEvent> {

        KeyCodeCombination copyKeyCodeCompination = new KeyCodeCombination(KeyCode.C, KeyCombination.CONTROL_ANY);
        public void handle(final KeyEvent keyEvent) {
            if (copyKeyCodeCompination.match(keyEvent)) {
                if (keyEvent.getSource() instanceof TableView) {
                    copySelectionToClipboard((TableView<?>) keyEvent.getSource());
                    keyEvent.consume();
                }
            }
        }
    }

    public static void copySelectionToClipboard(TableView<?> table) {
        final ClipboardContent clipboardContent = new ClipboardContent();
        clipboardContent.putString(getSelection(table));
        Clipboard.getSystemClipboard().setContent(clipboardContent);
    }

    public static void dragSelection(TableView<?> table) {
        String selection = getSelection(table);
        Dragboard dragboard = table.startDragAndDrop(TransferMode.COPY);
        ClipboardContent content = new ClipboardContent();
        content.putString(selection);
        dragboard.setContent(content);
    }

    public static String getSelection(TableView<?> table) {
        StringBuilder clipboardString = new StringBuilder();
        ObservableList<TablePosition> positionList = table.getSelectionModel().getSelectedCells();
        int prevRow = -1;
        for (TablePosition position : positionList) {

            int row = position.getRow();

            if (prevRow != -1) {
                clipboardString.append('\n');
            }
            String text = "";

            for (int i = 0; i < table.getColumns().size(); i++) {
                Object observableValue = (Object) table.getColumns().get(i).getCellObservableValue(row);

                if (observableValue == null) {
                    text += "";
                } else if (observableValue instanceof DoubleProperty) {

                    text += numberFormatter.format(((DoubleProperty) observableValue).get());

                } else if (observableValue instanceof IntegerProperty) {

                    text += numberFormatter.format(((IntegerProperty) observableValue).get());

                } else if (observableValue instanceof StringProperty) {

                    text += ((StringProperty) observableValue).get();

                } else {
                    System.out.println("Unsupported observable value: " + observableValue);
                }
                if (i != table.getColumns().size() - 1) {
                    text += "\t";
                }
            }

            clipboardString.append(text);

            prevRow = row;
        }

        return clipboardString.toString();
    }

}

テーブルの列の表示設定をするサブウィンドウを開く

JavaFX門中
TableViewのカラムを表示したり非表示したりする処理の共通化

package hoge;

import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableView;
import javafx.scene.input.MouseButton;

/**
 * テーブルを引数に取ってサブウィンドウを登録する
 */
public class ColumnVisibilityContextMenu {
    public ColumnVisibilityContextMenu(TableView tableView) {
        
        ColumnVisibilityEditAction visibilityAction = new ColumnVisibilityEditAction(tableView);
        
        MenuItem menuItem = new MenuItem("表示設定");
        menuItem.setOnAction(event -> {
            visibilityAction.doAction(event);
        });
        final ContextMenu contextMenu = extractContextMenu(tableView);
        contextMenu.getItems().add(menuItem);
        tableView.setOnMousePressed(me -> {
            if (me.getButton() == MouseButton.SECONDARY) {
                contextMenu.show(tableView.getParent(), me.getScreenX(), me.getScreenY());
            }
        });

    }
    
    private ContextMenu extractContextMenu(TableView tableView) {
        ContextMenu contextMenu = tableView.getContextMenu();
        if (contextMenu == null) {
            contextMenu = new ContextMenu();
        }
        return contextMenu;
    }
}
package hoge;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

/**
 * 処理本体
 */
public class ColumnVisibilityEditAction {

    private Stage stage;
    private ListView<String> visibleListView;
    private ObservableList<String> visibleList = FXCollections.observableArrayList();
    private ListView<String> invisibleListView;
    private ObservableList<String> invisibleList = FXCollections.observableArrayList();
    private final Button visibleButton;
    private final Button invisibleButton;
    private final Button saveButton;
    private final Button cancelButton;

    public ColumnVisibilityEditAction(TableView tableView) {
        visibleListView = new ListView<>(visibleList);
        visibleListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        invisibleListView = new ListView<>(invisibleList);
        invisibleListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

        this.load(tableView);
        visibleButton = new Button("<< 表示");
        visibleButton.setMinWidth(80);
        visibleButton.setOnAction(event -> {
            ObservableList<String> selectedItems = invisibleListView.getSelectionModel().getSelectedItems();
            visibleList.addAll(selectedItems);
            invisibleListView.getItems().removeAll(selectedItems);
        });
        invisibleButton = new Button("非表示 >>");
        invisibleButton.setMinWidth(80);
        invisibleButton.setOnAction(event -> {
            ObservableList<String> selectedItems = visibleListView.getSelectionModel().getSelectedItems();
            invisibleList.addAll(selectedItems);
            visibleListView.getItems().removeAll(selectedItems);
        });
        saveButton = new Button("適用");
        saveButton.setOnAction(event -> {
            for (Object c : tableView.getColumns()) {
                TableColumn column = (TableColumn) c;
                if (visibleList.contains(column.getText())) {
                    column.setVisible(true);
                } else {
                    column.setVisible(false);
                }
            }
            this.stage.hide();
        });
        cancelButton = new Button("キャンセル");
        cancelButton.setOnAction(event -> {
            this.stage.hide();
            this.load(tableView);
        });

        FlowPane buttonPane = new FlowPane(visibleButton, invisibleButton);
        buttonPane.setOrientation(Orientation.HORIZONTAL);
        buttonPane.setAlignment(Pos.CENTER);
        buttonPane.setMaxWidth(60);
        SplitPane editPane = new SplitPane(visibleListView, buttonPane, invisibleListView);
        editPane.setOrientation(Orientation.HORIZONTAL);

        FlowPane actionPane = new FlowPane(saveButton, cancelButton);
        actionPane.setAlignment(Pos.CENTER_RIGHT);
        actionPane.setMaxHeight(30);
        SplitPane mainPane = new SplitPane(editPane, actionPane);
        mainPane.setOrientation(Orientation.VERTICAL);

        Scene scene = new Scene(mainPane, 400, 300);
        stage = new Stage();
        stage.setScene(scene);
    }

    private void load(TableView tableView) {
        visibleList.clear();
        invisibleList.clear();
        for (Object c : tableView.getColumns()) {
            TableColumn column = (TableColumn) c;
            if (column.isVisible()) {
                visibleList.add(column.getText());
            } else {
                invisibleList.add(column.getText());
            }
        }
    }

    public void doAction(ActionEvent event) {
        stage.show();
    }
}

Dockerを認証Proxy配下でインストールする

基本的な流れはこの通り

Redirecting…

困る部分は、最初の Docker Quickstart Terminal で既にエラーになる。
pre-create でネットワークエラーになっている。

暫定対応としては、
Docker Quickstart Terminal で呼ばれているstart.shの先頭にproxy認証を直書きした。

#!/bin/bash
export HTTP_PROXY=http://user_id:password@proxy.domain:port

RaspberryPiにOpenJTalkをインストールする

まずはopen-jtalk本体のインストール

$ sudo apt-get install open-jtalk
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  libhtsengine1
Suggested packages:
  open-jtalk-mecab-naist-jdic hts-voice-nitech-jp-atr503-m001
The following NEW packages will be installed:
  libhtsengine1 open-jtalk
0 upgraded, 2 newly installed, 0 to remove and 97 not upgraded.
Need to get 187 kB of archives.
After this operation, 542 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://mirrordirector.raspbian.org/raspbian/ jessie/main libhtsengine1 armhf 1.08-1 [38.0 kB]
Get:2 http://mirrordirector.raspbian.org/raspbian/ jessie/main open-jtalk armhf 1.07-2 [149 kB]
Fetched 187 kB in 1s (132 kB/s) 
Selecting previously unselected package libhtsengine1.
(Reading database ... 124920 files and directories currently installed.)
Preparing to unpack .../libhtsengine1_1.08-1_armhf.deb ...
Unpacking libhtsengine1 (1.08-1) ...
Selecting previously unselected package open-jtalk.
Preparing to unpack .../open-jtalk_1.07-2_armhf.deb ...
Unpacking open-jtalk (1.07-2) ...
Processing triggers for man-db (2.7.0.2-5) ...
Setting up libhtsengine1 (1.08-1) ...
Setting up open-jtalk (1.07-2) ...
Processing triggers for libc-bin (2.19-18+deb8u1) ...

次に推奨パッケージの追加インストール

$ sudo apt-get install open-jtalk-mecab-naist-jdic hts-voice-nitech-jp-atr503-m001
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  hts-voice-nitech-jp-atr503-m001 open-jtalk-mecab-naist-jdic
0 upgraded, 2 newly installed, 0 to remove and 97 not upgraded.
Need to get 10.9 MB of archives.
After this operation, 68.2 MB of additional disk space will be used.
Get:1 http://mirrordirector.raspbian.org/raspbian/ jessie/main open-jtalk-mecab-naist-jdic all 1.07-2 [10.1 MB]
Get:2 http://mirrordirector.raspbian.org/raspbian/ jessie/contrib hts-voice-nitech-jp-atr503-m001 all 1.05-1 [764 kB]
Fetched 10.9 MB in 4s (2,617 kB/s)                       
Selecting previously unselected package open-jtalk-mecab-naist-jdic.
(Reading database ... 124936 files and directories currently installed.)
Preparing to unpack .../open-jtalk-mecab-naist-jdic_1.07-2_all.deb ...
Unpacking open-jtalk-mecab-naist-jdic (1.07-2) ...
Selecting previously unselected package hts-voice-nitech-jp-atr503-m001.
Preparing to unpack .../hts-voice-nitech-jp-atr503-m001_1.05-1_all.deb ...
Unpacking hts-voice-nitech-jp-atr503-m001 (1.05-1) ...
Setting up open-jtalk-mecab-naist-jdic (1.07-2) ...
Setting up hts-voice-nitech-jp-atr503-m001 (1.05-1) ...

これだけだと音が出来ないので、参考リンクの内容を実行。

Raspberry Piで音を出すまで - Qiita

$ cd /opt/vc/src/hello_pi/
$ ./rebuild.sh
$ speaker-test -t sine -f 600

waveのテスト。音がものすごく小さくて聞き取りが難しかった。

$ aplay /usr/share/sounds/alsa/Rear_Center.wav

ボリュームを調整する。以下のコマンドを実行するとダイアログが出るので上下させて調整する。

$ alsamixer -c 0

後はOpenJtalkでwavを作ってaplayで再生すれば発話する。
openjtalkはパラメータが非常に多い。
Ubuntu Open JTalk その2 - open_jtalkコマンドの説明 - kledgeb

$ vi say.sh

#!/bin/sh

if [ $# -ne 1 ]; then
  echo "invalid arguments. Usage: bash say.sh 'input_text'"
  exit 1;
fi

TMP=$($(cd $(dirname $0));pwd)/jsay.wav

echo "$1" | open_jtalk \
-m /usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice \
-x /var/lib/mecab/dic/open-jtalk/naist-jdic \
-ow $TMP && \
aplay --quiet $TMP
rm -f $TMP

ローカルディレクトリにOpenJtalkでwaveファイルを作って、aplayで再生。
再生が終わったら削除する。

実行権限を付ける。

$ chmod u+x say.sh

使い方。

$ ./say.sh "ようやく話せるようになりました。ありがとうございます。"

続きはまた次回。

EC2にRedmineをインストールする

Amazon EC2上にRedmineをインストールしてみた | DevelopersIO
AWSのEC2にALMiniumをインストールしたときのいろいろ – doop

$ sudo yum install httpd
$ sudo yum -y install mysql-server mysql-devel
[mysqld]
character-set-server=utf8
[mysql]
default-character-set=utf8
$ sudo service mysqld start
$ sudo chkconfig mysqld on
$ mysql -uroot
mysql> create database db_redmine default character set utf8;
mysql> grant all on db_redmine.* to db_username@localhost identified by 'db_password';
mysql> quit
$ sudo yum -y groupinstall "Development Tools"
$ sudo yum -y --enablerepo=epel install ruby-devel ImageMagick ImageMagick-devel ipa-gothic-fonts
$ gem install bundler --no-rdoc --no-ri
$ gem install io-console
$ mkdir tmp
$ cd tmp
$ curl -O http://www.redmine.org/releases/redmine-3.0.3.tar.gz
$ tar xvf redmine-3.0.3.tar.gz 
$ sudo mv redmine-3.0.3 /var/lib/redmine
$ cd /var/lib/redmine
$ bundle install --without development test
production:
  adapter: mysql2
  database: db_redmine
  host: localhost
  username: db_username
  password: db_password
  encoding: utf8
$ gem install mysql2
$ bundle install
$ bundle exec rake generate_secret_token
$ bundle exec rake db:migrate RAILS_ENV=production
$ bundle exec rake db:migrate RAILS_ENV=production
$ sudo yum -y install curl-devel httpd-devel apr-devel apr-util-devel
$ gem install passenger --no-rdoc --no-ri
$ sudo chmod o+x "/home/ec2-user"
$ sudo dd if=/dev/zero of=/swap bs=1M count=2048
$ sudo mkswap /swap
$ sudo swapon /swap

$ passenger-install-apache2-module

出力される設定をコピー。
/etc/httpd/conf.d/passenger.confに貼り付け。
以下も追加。

RackBaseURI /redmine
$ sudo ln -s /var/lib/redmine/public /var/www/html/redmine
$ sudo service httpd configtest
$ sudo service httpd restart

http://サーバー名/redmine


2016/02/15 追記
結局bitnamiのAMIから作り直した。その方がスムーズだった。