Wordpressコンテナのhttps化

社内開発用にdockerのwordpressコンテナでたてたサイトにhttpsアクセスできるようにしたので備忘録に。
dockerコンテナでなければnginxでSSL処理して、WordPressにプロクシーしてWordpressの設定でサイトURLをhttpsにすればよかったと思う。

しかし、dockerコンテナでssl化となると単純にいかず調べてみたところ、
1. docker-composeでnginxコンテナも一緒に立ててSSL処理をコンテナ内部でも行うようにする。wordpressコンテナ側はhttpsでリクエストが来る前提で単純設定のみで行う。
2. nginxはプロセスで動かしhttpsでリクエスト処理はこの中だけで完結させ、httpでwordpressコンテナにプロクシーする。wordpress側は各URIはhttpsになるようにしつつ、サイトURLはプロクシーURLのhttpで行えるようにする。

docker経験が浅いのでいまだcomposeが理解できず、2の方法をとりました。

##ハマッたこと
1. たぶん正攻法でないやり方だったため、wordpressの中でサイトURLとリンクURLを分ける必要にかられ、データの修正だけでは対応できずソースをいじる必要にかられたこと。
2. nginxでもしかしたらクライアントに返すリソースURLを書き換える？なんてことができればとも思ったが、ページ中のリンクはどうしようもないよな・・ないよね？（わかる人いたら教えてください）
3. mixed　contentsで各リソースはプロクシーまかせにできず、こちらもソースの修正で対応したこと。


ここから実際にやったことを記録しておく。たぶん直し方もWordPressのお作法に則っていない箇所があると思う。あくまで動けばいいやで割り切って対応した。
製作要件によってはこれだけでは対応できないところがあるかもしれない。

※[「Redmineコンテナのhttps化」][link-1] に続いて行った。
　下記はここからの差分である。
[link-1]:https://qiita.com/oko1977/items/4b7797a1d2df26f996e5

##nginx側
裏のコンテナにアクセスできるURLでプロクシーさせる。
おまじないで強制的にhttpsでリソースを読み込ませるために、
「add_header Content-Security-Policy upgrade-insecure-requests」を追加しておく。

```nginx.conf
    server {
        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

　　　　(中略)

        #wpサーバ
+        location ^~ /wp/ {    #"/wp/"で前方一致する場合
+            add_header Content-Security-Policy upgrade-insecure-requests;
+            proxy_pass http://domain:port/wp/;
+        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
```

##wordpressコンテナ側

###db

`wp_optionsテーブル`

|option_name  |option_value  |
|---|---|---|
|siteurl  |nginxのプロクシーURL  |
|home  |nginxのプロクシーURL  |
|ssl_url|公開するhttpsのURL |　
※ssl_urlのレコードは追加

###apache
エイリアスを付与してサブディレクトリがあってもなくてもサイトにアクセスできるようにする。（ドキュメントルートにフォルダを一つ追加する方法で対応したり、シンボリックリンクフォルダでやってみたが、トップページ以外にアクセスできなかったので）

```html:/etc/apache2/apache2.conf

（中略）

<Directory /usr/share>
        AllowOverride None
        Require all granted
</Directory>

<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
</Directory>

+Alias /wp/ "/var/www/html/"
+<Directory /var/www/html/>
+  Allow from all
+</Directory>

（中略）
```

再起動しておく

```
service apache2 restart
```

###ここからソース修正

tips
ソースはHTMLコンテンツのclass名やid名でgrepしてあたりを付けました。
その時に役に立ったのが以下のコマンド。サブディレクトリも含めて拡張子がphpの中からgrepしてくれます。

`find [検索対象ディレクトリ] -name "*.php" -type f -print | xargs grep '[検索ワード]'`



```php3:wp-admin/includes/options.php
(中略)

/**
 * Display JavaScript on the page.
 *
 * @since 3.5.0
 */
function options_general_add_js() {
  ?>
<script type="text/javascript">
  jQuery(document).ready(function($){
  var $siteName = $( '#wp-admin-bar-site-name' ).children( 'a' ).first(),
- homeURL = ( <?php echo wp_json_encode( get_home_url() ); ?> || '' ).replace( /^(https?:\/\/)?(www\.)?/, '' );
+  homeURL = ( <?php echo wp_json_encode( get_option( 'ssl_url' ) ); ?> || '' ).replace( /^(https?:\/\/)?(www\.)?/, '' );
  $( '#blogname' ).on( 'input', function() {
    var title = $.trim( $( this ).val() ) || homeURL;

(中略)
```

```php3:wp-includes/admin-bar.php
(中略)


/**
 * Add the "Site Name" menu.
 *
 * @since 3.3.0
 *
 * @param WP_Admin_Bar $wp_admin_bar
 */
function wp_admin_bar_site_menu( $wp_admin_bar ) {
	// Don't show for logged out users.
	if ( ! is_user_logged_in() ) {
		return;
	}

(中略)

	$wp_admin_bar->add_menu(
	  array(
	    'id'    => 'site-name',
	    'title' => $title,
-	    'href'  => ( is_admin() || ! current_user_can( 'read' ) ) ? home_url( '/' ) : admin_url(),
+	    'href'  => ( is_admin() || ! current_user_can( 'read' ) ) ? get_option( 'ssl_url' ) : admin_url(),
		)
	);

	// Create submenu items.

	if ( is_admin() ) {
	  // Add an option to visit the site.
	  $wp_admin_bar->add_menu(
	    array(
	      'parent' => 'site-name',
	      'id'     => 'view-site',
	      'title'  => __( 'Visit Site' ),
-	      'href'   => home_url( '/' ),
+	      'href'   => get_option( 'ssl_url' ),
            )
	  );

(中略)
```

```php3:wp-includes/link-template.php
(中略)

/**
 * Retrieves the URL for a given site where WordPress application files
 * (e.g. wp-blog-header.php or the wp-admin/ folder) are accessible.
 *
 * Returns the 'site_url' option with the appropriate protocol, 'https' if
 * is_ssl() and 'http' otherwise. If `$scheme` is 'http' or 'https',
 * `is_ssl()` is overridden.
 *
 * @since 3.0.0
 *
 * @param int    $blog_id Optional. Site ID. Default null (current site).
 * @param string $path    Optional. Path relative to the site URL. Default empty.
 * @param string $scheme  Optional. Scheme to give the site URL context. Accepts
 *                        'http', 'https', 'login', 'login_post', 'admin', or
 *                        'relative'. Default null.
 * @return string Site URL link with optional path appended.
 */
function get_site_url( $blog_id = null, $path = '', $scheme = null ) {
	if ( empty( $blog_id ) || ! is_multisite() ) {
-		$url = get_option( 'siteurl' );
+		$url = get_option( 'ssl_url' );
	} else {
		switch_to_blog( $blog_id );
-		$url = get_option( 'siteurl' );
+		$url = get_option( 'ssl_url' );
		restore_current_blog();
	}

(中略)

/**
 * Sets the scheme for a URL.
 *
 * @since 3.4.0
 * @since 4.4.0 The 'rest' scheme was added.
 *
 * @param string      $url    Absolute URL that includes a scheme
 * @param string|null $scheme Optional. Scheme to give $url. Currently 'http', 'https', 'login',
 *                            'login_post', 'admin', 'relative', 'rest', 'rpc', or null. Default null.
 * @return string $url URL with chosen scheme.
 */
function set_url_scheme( $url, $scheme = null ) {
	$orig_scheme = $scheme;

	if ( ! $scheme ) {
		$scheme = is_ssl() ? 'https' : 'http';
	} elseif ( $scheme === 'admin' || $scheme === 'login' || $scheme === 'login_post' || $scheme === 'rpc' ) {
		$scheme = is_ssl() || force_ssl_admin() ? 'https' : 'http';
	} elseif ( $scheme !== 'http' && $scheme !== 'https' && $scheme !== 'relative' ) {
		$scheme = is_ssl() ? 'https' : 'http';
	}

+	$scheme = 'https';

	$url = trim( $url );
	if ( substr( $url, 0, 2 ) === '//' ) {
		$url = 'http:' . $url;
	}

(中略)
```

```php3:wp-includes/script-loader.php
(中略)

/**
 * Register all WordPress scripts.
 *
 * Localizes some of them.
 * args order: `$scripts->add( 'handle', 'url', 'dependencies', 'query-string', 1 );`
 * when last arg === 1 queues the script for the footer
 *
 * @since 2.6.0
 *
 * @param WP_Scripts $scripts WP_Scripts object.
 */
function wp_default_scripts( &$scripts ) {
	$suffix     = wp_scripts_get_suffix();
	$dev_suffix = wp_scripts_get_suffix( 'dev' );

	if ( ! $guessurl = site_url() ) {
		$guessed_url = true;
		$guessurl    = wp_guess_url();
	}

-	$scripts->base_url        = $guessurl;
+	$scripts->base_url        = get_option( 'ssl_url' );
	$scripts->content_url     = defined( 'WP_CONTENT_URL' ) ? WP_CONTENT_URL : '';
	$scripts->default_version = get_bloginfo( 'version' );
	$scripts->default_dirs    = array( '/wp-admin/js/', '/wp-includes/js/' );

(中略)
```

```php3:wp-includes/theme.php
(中略)

/**
 * Retrieve URI for themes directory.
 *
 * Does not have trailing slash.
 *
 * @since 1.5.0
 *
 * @global array $wp_theme_directories
 *
 * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
 *                                       Default is to leverage the main theme root.
 * @param string $theme_root             Optional. The theme root for which calculations will be based, preventing
 *                                       the need for a get_raw_theme_root() call.
 * @return string Themes URI.
 */
function get_theme_root_uri( $stylesheet_or_template = false, $theme_root = false ) {
	global $wp_theme_directories;

+	return get_option('ssl_url')."/wp-content/themes";

	if ( $stylesheet_or_template && ! $theme_root ) {
		$theme_root = get_raw_theme_root( $stylesheet_or_template );
	}
(中略)
```

```php3:wp-login.php
(中略)

/**
 * Outputs the footer for the login page.
 *
 * @since 3.1.0
 *
 * @param string $input_id Which input to auto-focus.
 */
function login_footer( $input_id = '' ) {
	global $interim_login;

	// Don't allow interim logins to navigate away from the page.
	if ( ! $interim_login ) :
		?>
-	<p id="backtoblog"><a href="<?php echo esc_url( home_url( '/' ) ); ?>">
+	<p id="backtoblog"><a href="<?php echo esc_url( get_option( 'ssl_url' ) ); ?>">
		<?php
		/* translators: %s: site title */
		printf( _x( '&larr; Back to %s', 'site' ), get_bloginfo( 'title', 'display' ) );
		?>

(中略)
```

以上です。