【Linux】~/.bash_profileや~/.bashrcなどの起動順序

ステップシステム全体の設定ファイルユーザ毎の設定ファイル
1. ログインシェル起動時/etc/profile-
(2. Debian系のみ)/etc/bash.bashrc-
3. ~/.bash_profileがある場合-~/.bash_profile
4. ~ /.bash_loginがある場合-~/.bash_login
5. ~/.profileがある場合-~/.profile
6. ~/.bashrcがある場合-~/.bashrc
7. ログインシェル起動完了--
8. ログアウト時-~/.bash_logout

【Linux】SUID, SGID, スティッキービット

SUID

SUID(Set User ID)とは、実行権のあるファイルに設定されている特殊なアクセス権のこと。

例えば、一般ユーザ(rootでないユーザ)が自身のパスワードを変更すると、この変更は/etc/passwdファイルに保存されます。そこで、/etc/passwdファイルのパーミションを見ると以下のようになっています。

$ ls -l /etc/passwd
-rw-r--r-- 1 root root 667 Apr 21 00:21 /etc/passwd


このファイルの所有者はrootで、rootのみ書込み可であることがわかります。
これによると、一般ユーザは/etc/passwdに書き込みができないように思えますが、ここでpasswdコマンドを調べると、

$ ls -l `which passwd`
-rws--x--x 1 root bin 4731 Mar 09 10:43 /usr/bin/passwd


所有者のアクセス権が”rws”となっています。実行権の部分がsとなっていますが、これは実行権を持っているユーザによってプログラムが実行された場合は、ファイルの所有者の権限で実行されることを意味します。これをSUIDと呼びます。

つまり、一般ユーザはpasswdの実行権を持っているので、passwdが/etc/passwdに書き込む際はそのファイルの所有者であるrootの権限(rw)で実行されることになりますSUIDが設定されると、所有者の実行権限にsが入り、8進数表記にすると4000になります。なので、/usr/bin/passwdの権限は4611となります。

SGID

SGID(Set Group ID)は、SUIDと同じことが所有グループに適用され、所有グループの実行権にsが入ります。8進数表記だと2000です。

スティッキービット

スティッキービットは、特定のディレクトリに対しアクセス権が許可されていてもファイルの削除は行えないようにする設定です。

/tmpのアクセス権を見ると、

$ ls -ld /tmp
drwxrwxrwt 1 root root 4096 Apr 21 23:45 /tmp


となっており、その他のユーザの実行権がtとなっています。これがスティッキービットで、これによりその他のユーザに読み取り書込み権限があっても、自分以外のユーザが所有するファイルを削除することはできなくなります。

スティッキービットは8進数表記だと1000になります。なので、/tmpの権限は1777です。

まとめ

名称権限8進数表記
SUID所有者の実行権限にs ( e.g. -rws--x--x )4000
SGID所有グループの実行権限にs ( e.g. -rwx--s--x )2000
スティッキービットその他のユーザの実行権限にt ( e.g. drwxrwxwt )1000

【Linux】標準出力と標準エラー出力は何が違う?

Linuxの標準入出力について

Linuxでは、データのストリーム(データの入出力に伴うデータの流れのこと)を扱うために以下のように、標準出力/標準出力/標準エラー出力の3つの経路(インターフェース)が用意されています.

ファイル・ディスクリプタ番号入出力名
0標準入力
1標準出力
2標準エラー出力

ファイル・ディスクリプタとは、OSが標準入出力の種類を識別するための識別子です.

以下は標準出力と標準エラー入力を出力する例です.

std_out_err.sh

#!bin/bash
echo "標準出力" >&1 # 標準出力
echo "標準エラー出力" >&2 # 標準エラー出力

以下のようにすると、標準出力の内容をファイルへ書き込み、標準エラー出力を端末に表示できます.

$ sh std_out_err.sh > std_out.log
標準エラー出力
$ cat std_out.log
標準出力

>はリダイレクトを意味します. リダイレクトとは、データの入出力をコントロールする機能で、上の例ではechoの標準出力をstd_out.logに書き出す処理をしています.

> は 1> と同義で、1>は標準出力のリダイレクトを意味します. 2> とすると標準エラー出力をリダイレクトできます.

また、以下のように>&を使うと、標準出力と標準エラー出力どちらもリダイレクトできます.

$ sh std_out_err.sh >& std_out_err.log
$ cat std_out_err.log
標準出力
標準エラー出力


なぜ標準出力と標準エラー出力を分けている?

ここで、エラーとそれ以外でデータの経路を分けている理由を何でしょうか.
それは、上の例のように、エラーとそれ以外の出し分けが簡単になるからです.

例えば、毎日実施するバッチがあったとすると、標準出力は必要なくエラーのみログに保存されていて欲しい、ということがあると思います.

この場合は以下のようにすると、標準出力を捨て、エラーのみログに残すことができます.

$ sh std_out_err.sh 2> std_err.log > /dev/null
$ cat std_err.log
標準エラー出力

* /dev/null はnullデバイスと呼ばれ、ここに書き込まれたデータは全て捨てられます.

標準出力と標準エラー出力の経路を別にすることで(1, 2で分けている)、ストリームの扱いが簡潔になります.

Origin(オリジン)とは

Originとは、URLのスキームドメインポートの3つによって定義され、それらが全て一致した場合に、その2つのオブジェクトは同じオリジンといいます。

ちなみに、https://example.com:8080 というURLがあった時、httpsをスキーム、example.comドメイン、8080をポートと呼びます。

例えば、以下のURLは同一オリジン

http://example.com
http://example.com:80
スキーム、ドメイン、ポートが同じなので同一オリジン
http://example.com/post/1
http://example.com/post/2
同上

以下のURLは異なるオリジンです。

http://example.com
https://example.com
スキームが異なる
http://example.com
http://examples.com
ドメインが異なる
http://example.com
http://example.com:8080
ポートが異なる

dbに接続できない - could not connect to server

Dockerを使ってRails6の環境を作り、docker-compose upで起動すると、以下のようなエラーが表示されました。

PG::ConnectionBad: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

原因と解決策

調べてみるとこれは、railsがホストマシーンに接続しようとしていることが原因でした。ということでrailsのconfig/database.ymlを確認すると、username/password/hostを指定し忘れていました。

default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  # username/password/hostを指定してない!


なので、docker-compose.ymlで指定している値をdatabase.ymlに設定してあげます。

version: "3"

services:
  postgres:
      image: postgres
      environment:
        POSTGRES_USER: 'admin'
        POSTGRES_PASSWORD: 'admin-pass'
      restart: always
 ...


image名、POSTGRES_USER, POSTGRES_PASSWORDの値を、database.ymlにも指定します。

default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: admin
  password: admin
  host: postgres


これで無事アクセスに成功しました。

Next.js - プリレンダリングについて

Next.jsのプレリンダリングについて学んだので忘備録として残します。

プリレンダリングとは

Next.jsにおいて、最も重要な概念はプリレンダリング(pre-rendering)です。

Next.jsは、デフォルトで全てのページでプリレンダリングします。
これは、クライアントサイド(ブラウザ)でJavaScriptがページを逐一レンダリングするのではなく、予め全てのページのHTMLを生成する、ということです。これによりSEOがより良くなります。

プリレンダリング時には、HTMLは必要最低限のJavaScriptコードとともに生成されており、ブラウザによるロード時にこのJavaScriptが動き、ページが完全にインタラクティブなものになります。これをハイドレーション(hydration)と呼びます。

なので、ブラウザの設定でJavaScriptを無効にしてNext.jsアプリのページを表示すると、staticなHTMLのみが表示されます。

一方、Next.jsではなくReactのみのアプリだと、JavaScript無効のブラウザでは動きません。React単体にはプリレンダリング機能はないからです。

プリレンダリングには、以下の2種類があります。

  • 静的生成(Static-site Generation: SSG)
  • サーバサイドレンダリング(Server-side Rendering: SSR)

静的生成(Static Generation)

これはビルド時にHTMLを生成するプリレンダリング方法です。リクエスト時にこのプリレンダリングされたHTMLを返します。

サーバサイドレンダリング(SSR)

これはリクエスト時にHTMLを生成するプリレンダリング方法です。

Next.jsでは、それぞれのページにつきどちらの方法でプリレンダリングするか選べますが、やはり静的生成の方が速いので、Next.jsは可能な限り静的生成を使うよう推奨しているようです。

一方、リクエスト毎に表示が変わるようなページはリクエスト毎にプリレンダリングするSSRの方が適しているので、このような場合はSSRを使うなど、「リクエスト前にプリレンダリングできるかどうか」を考えて選択する必要があります。

参考:

https://nextjs.org/learn/basics/data-fetching/pre-rendering

Dockerでコンテナ化したrailsアプリをproductionモードで起動する

Dockerでコンテナ化したrailsアプリをproductionモード(本番環境)で起動する方法をメモします。

productionモードとして起動するには以下のような設定項目があります。

  • production用docker-compose.ymlを用意
  • DB設定ファイルの編集(config/database.yml)
  • secret_key_baseの準備
  • Gemfileの編集
  • DBのセットアップ
  • アセットのプリコンパイル

以下で一つずつ解説していきます。

production用docker-compose.ymlを用意

ファイル名をdocker-compose.prd.ymlとしてproduction用のdocker-compose設定ファイルを準備します。

version: '3'
services:
  ...
  app:
    ...
    # 以下を含める
    environment:
     RAILS_ENV: production
    ...


DBの設定

以下のように、config/database.ymlにproduction用にデータベースの設定を追記します。

production:
  <<: *default
  database: データベース名
  username: ユーザ名
  password: パスワード


secret_key_baseの準備

既にcredentials.yml.encが存在していれば、secret_key_baseは記述されているかと思うので内容を確認します。seret_key_baseはconfig/master.keyによって暗号化されているのでそのままでは中身を見ることはできないので以下を実行。

// コンテナ内に入る
$ docker exec -it コンテナID bash
(コンテナ内)> EDITOR="vim" bin/rails credentials:edit


EDITOR="vim"でエディターを指定します。もしvimの編集モードでファイルが開かずNew credentials encrypted and saved.とだけ返って来るようなら、コンテナにvimがないことが原因の場合があるのでvimをインストールします。(e.g. apt-get install vim)

credentials.yml.encが開ければ、以下のようにsecret_key_baseがあることを確認します。

# aws:
#   access_key_id: 123
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: キー


Gemfileの編集

以下のように、production環境のみで使いたいgem, またはtest/development環境のみで使うgemを含めないよう設定します。

group :production do
  gem 'xxx',
  gem 'yyy',
 ・・・
end


DBのセットアップ

docker-compose runコマンドで、rails db:setをproduction向けに実行します。appは各自のコンテナ名に置き換えてください。

$ docker-compose run app rails  db:setup RAILS_ENV=production
Creating docker_rails_app_run ... done
Created database 'prd_database'

$ docker-compose -f docker-compose.prd.yml exec app rails db:create
$ docker-compose -f docker-compose.prd.yml exec app rails db:migrate


アセットのプリコンパイル

静的ファイルをプリコンパイルをします。

$ docker-compose run app rails assets:precompile RAILS_ENV=production

ここまでできたら、docker-compose.prd.ymlを指定してproductionモードで起動してみます。

$ docker-compose -f docker-compose.prd.yml up --build