systemd/User (日本語) - ArchWiki

# systemd/User (日本語)

関連記事

- systemd
- 仮想コンソールに自動ログイン
- ログイン時に X を起動する

systemd はユーザーに systemd のインスタンスを実行させてサービスを管理できる機能を提供しています。これによって systemd がユーザーによって実行されている時、特定のディレクトリに入っているユニットをユーザーが起動・停止・有効化・無効化することが可能です。このことは root や特別なユーザーではなく普通のユーザーとして通常実行される mpd などのデーモン・サービスで重宝します。また、メールの取得などの作業を自動化することも可能です。さらに、多少の注意が必要ですが、ユーザーサービスから xorg やウィンドウマネージャを実行することもできます。

## 利用方法

ユーザーがログインを行うと、systemd は自動的にユーザーサービスを管理する `systemd --user` インスタンスを起動します。このプロセスは、そのユーザーにセッションが残っているかぎり生存し、ユーザーの最後のセッションが閉じられた時に終了します。systemd のユーザーインスタンスを自動起動している場合、インスタンスはブート時に起動し、終了しません。デフォルトではユーザーサービスは何も実行されません。ユーザーサービスを使うことで、ソケットアクティベーションやタイマー、システムの依存関係や cgroups によるプロセスの制限など、systemd の恩恵を最大限活用して、デーモンや自動化されたタスクを実行できます。ユーザーユニットはシステムサービスと同じように以下のディレクトリに配置されます (優先度が低い順):

- `/usr/lib/systemd/user/`: インストールしたパッケージに含まれているサービス
- `/etc/systemd/user/`: システムの管理者が配置する、全てのユーザーが使えるユーザーサービス
- `~/.config/systemd/user/`: ユーザーが配置する、そのユーザーのサービス

systemd のユーザーインスタンスが起動すると、`default.target` ターゲットが立ち上がります。その後 `systemctl --user` を使って手動で systemd のユーザーインスタンスを制御できるようになります。

Warning: `systemd --user` インスタンスはユーザーごとのプロセスであり、セッションごとのプロセスではないので注意してください。ソケットやステートファイルなどのユーザーサービスによって扱われるリソースはセッションごとではなくユーザーごとに割り振られる (ユーザーのホームディレクトリ上に存在する) というのが原則です。つまりユーザーサービスは全てセッションとは関係なく動作します。結果として、セッションの中で実行する必要があるプログラムはユーザーサービスの中で壊れてしまう可能性があります。systemd のユーザーセッションの扱い方は流動的であり確定していません。[1] や [2] が今後どうなるかのヒントになるでしょう。

## 基本設定

Systemd のユーザーインスタンスはログイン時に自動で起動します。正しく起動していることを確認するには、次のコマンドを使います: `systemctl --user status`。

Note: systemd のユーザーインスタンスが自動で実行されない場合 `/etc/pam.d/system-login` ファイルを確認してください。このファイルには `-session optional pam_systemd.so` というような行が含まれていなくてはなりません。.pacnew ファイルが存在していないかチェックしてください。

ユーザーサービスは全て `~/.config/systemd/user` に配置してください。ログイン時にサービスを実行したい場合は、自動実行したいサービスごとに `systemctl --user enable service` を実行してください。

Note: バージョン 206 から、systemd のユーザーインスタンスの仕組みは変更されています。現在、デフォルトで `pam_systemd.so` モジュールがユーザーインスタンスを起動します。手動で起動する必要はありません。user-session-units の `user-session@.service` は廃止されました。この変更によって `systemd --user` はユーザーセッションの外で実行されます。

### D-Bus

プログラムによっては D-Bus ユーザーメッセージバスを必要とすることがあります。D-Bus は伝統的に `dbus-launch` によってデスクトップ環境の起動時に実行されています。しかしながら、D-Bus に依存するプログラムを systemd のユーザーサービスとして使う場合、依存関係を解決するために D-Bus サーバーも systemd サービスとして実行する必要が出てきます。

Note: 将来 systemd から kdbus への移行がされることで、systemd はシステムとユーザーのメッセージバスのマネージャになります。

D-Bus を systemd サービスとして設定するには、以下を行う必要があります:

1. dbus サーバーのサービスユニットとソケットユニットを `/etc/systemd/user/` に追加:

    /etc/systemd/user/dbus.socket

    [Unit]
    Description=D-Bus Message Bus Socket
    Before=sockets.target

    [Socket]
    ListenStream=%t/dbus/user_bus_socket

    [Install]
    WantedBy=default.target

    /etc/systemd/user/dbus.service

    [Unit]
    Description=D-Bus Message Bus
    Requires=dbus.socket

    [Service]
    ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
    ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig

2. 環境変数 `DBUS_SESSION_BUS_ADDRESS` を設定。以下のファイルを作成して、`user@.service` の設定ファイルを使うことで設定できます:

    /etc/systemd/system/user@.service.d/dbus.conf

    [Service]
    Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%I/dbus/user_bus_socket

Note: systemd 209 以前は `DBUS_SESSION_BUS_ADDRESS` は上流の `user@.service` ユニットで設定されていました。現在は異なります。kdbus への移行が完了したら、`pam_systemd.so` によって変数が設定されるようになるから、というのが理由のようです。

3. root で以下を実行してソケットを有効化:

    # systemctl --global enable dbus.socket

### 環境変数

systemd のユーザーインスタンスは `.bashrc` などに設定された環境変数を全く継承しません。systemd インスタンスに環境変数を設定する方法は3つあります:

1. `/etc/systemd/user.conf` で `DefaultEnvironment` オプションを使う。全てのユーザーユニットに影響します。
2. `/etc/systemd/system/user@.service.d/` に設定ファイルを追加する。てのユーザーユニットに影響します。
3. 適宜、`systemctl --user set-environment` や `systemctl --user import-environment` を使う。環境変数を設定した後に起動したユーザーユニットには影響しますが、既に起動しているユニットには影響しません。

    Tip: 複数の変数を一度に設定するには、空白で区切った key=value ペアのリストを設定ファイルに書き込んで、`xargs systemctl --user set-environment < /path/to/file.conf` をシェルのスタートアップファイルに追加してください。

設定するべき変数としては `DISPLAY` や `PATH` などが考えられます。

#### DISPLAY

DISPLAY は X アプリケーションがどのディスプレイを使えばいいのか知るために使用されます。systemd ユニットから X アプリケーションを起動するつもりならば、この変数を設定しなくてはなりません。例:

    /etc/systemd/user.conf

    ...
    DefaultEnvironment=DISPLAY=:0
    ...

#### PATH

`PATH` 変数を `.bashrc` や `.bash_profile` で設定しても systemd では使うことができません。`PATH` をカスタマイズしており、それを利用するアプリケーションを systemd ユニットから起動する予定があるなら、systemd 環境に `PATH` を設定する必要があります。`PATH` を `.bash_profile` に設定している場合、以下を `PATH` 変数を設定した後の `.bash_profile` に追加するのが systemd で `PATH` を設定する一番簡単な方法です:

    ~/.bash_profile

    systemctl --user import-environment PATH

### systemd のユーザーインスタンスを自動起動

systemd のユーザーインスタンスはデフォルトでユーザーの最初のログイン時に実行され、ユーザーのセッションが閉じられた時に終了します。しかしながら、ブートした直後にインスタンスを起動して、セッションが閉じられてもユーザーインスタンスを実行し続ける方が、例えばセッションが開いてない時もユーザープロセスを実行したいときなどには便利です。linger を利用してこれを行います。特定のユーザーで linger を有効にするには以下のコマンドを使用:

    # loginctl enable-linger username

Warning: systemd のサービスはセッションではありません。サービスは logind の外で動作します。linger を利用して自動ログインを有効にするとセッションが破壊されるので注意してください。

## Xorg と systemd

systemd ユニットの中で Xorg を実行する方法は複数存在します。以下の2つは、xorg プロセスで新しいユーザーセッションを起動するというのと、systemd のユーザーサービスから xorg を起動するという方法です。

### ディスプレイマネージャを使わずに Xorg に自動ログイン

こちらを選択した場合、xorg サーバーでユーザーセッションを起動してその後ウィンドウマネージャなどを起動するために通常の `~/.xinitrc` を実行するシステムユニットを起動します。

D-Bus を適切に設定して xlogin-git をインストールする必要があります。

雛形のファイルから xinitrc を設定して、`/etc/X11/xinit/xinitrc.d/` のファイルが読み込まれるようにしてください。`~/.xinitrc` は実行したときに戻ってこないようにする必要があるため、最後のコマンドとして `wait` を記述するか、(ウィンドウマネージャなど) `exec` を追加して戻ってこないようにしてください。

セッションは自らの dbus デーモンを使用しますが、systemd ユーティリティには `dbus.service` インスタンスが必要です。この問題を解決するにはコマンドのエイリアスを作成します:

    ~/.bashrc

    for sd_cmd in systemctl systemd-analyze systemd-run; do
        alias $sd_cmd='DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/dbus/user_bus_socket" '$sd_cmd
    done

最後に、(root で) xlogin を有効にして起動時に自動ログインするようにしてください:

    # systemctl enable xlogin@username

ユーザーセッションが systemd の範囲の中に収まるようになってユーザーセッションの全てが問題なく動作するはずです。

### systemd のユーザーサービスとしての Xorg

また、systemd のユーザーサービスの中から Xorg を実行することもできます。他の X 関連のユニットを Xorg などに依存させることができるという点では有利な一方、以下で説明するようにいくつか欠点が存在します。

バージョン 1.16 から xorg-server は systemd とのより良い統合を2つの手段で提供しています:

- デバイス管理を logind に委託することで、非特権でも実行することが可能に (このコミット など Hans de Goede のコミットを参照)。
- ソケットによってサービスを有効化することが可能に (このコミット を参照)。これによって systemd-xorg-launch-helper-git が不要に。

残念ながら、非特権モードで xorg を実行できるようにするには、セッションの中で xorg を実行する必要があります。そのため、今のところユーザーサービスとして xorg を実行するのには (1.16 以前と同じように) root 権限で実行する必要があるというハンディキャップがあり、1.16 で導入された非特権モードを活用することはできません。

Note: This is not a fundamental restriction imposed by logind, but the reason seems to be that xorg needs to know which session to take over, and right now it gets this information calling logind's `GetSessionByPID` using its own pid as argument. See this thread and xorg sources. It seems likely that xorg could be modified to get the session from the tty it is attaching to, and then it could run unprivileged from a user service outside a session.

以下がユーザーサービスから xorg を起動する方法です:

1. `/etc/X11/Xwrapper.config` を編集して、xorg が root 権限を使ってどのユーザーでも動作するようにします:

    /etc/X11/Xwrapper.config

    allowed_users=anybody
    needs_root_rights=yes

2. 以下のユニットを `~/.config/systemd/user` に追加:

    ~/.config/systemd/user/xorg@.socket

    [Unit]
    Description=Socket for xorg at display %i

    [Socket]
    ListenStream=/tmp/.X11-unix/X%i

    ~/.config/systemd/user/xorg@.service

    [Unit]
    Description=Xorg server at display %i

    Requires=xorg@%i.socket
    After=xorg@%i.socket

    [Service]
    Type=simple
    SuccessExitStatus=0 1

    ExecStart=/usr/bin/Xorg :%i -nolisten tcp -noreset -verbose 2 "vt${XDG_VTNR}"

`${XDG_VTNR}` は xorg が起動する仮想ターミナルで、サービスユニットでハードコードするか、以下のコマンドを使って systemd 環境で設定します:

    $ systemctl --user set-environment XDG_VTNR=1

Note: xorg はユーザーがログインしたのと同じ仮想ターミナルで起動する必要があります。そうでないと logind はセッションがアクティブになっていないと認識します。

3. 上で説明されているように `DISPLAY` 環境変数を設定します。

4. 次に、display 0 と tty 2 で xorg のソケットアクティベーションを有効化します:

    $ systemctl --user set-environment XDG_VTNR=2     # So that xorg@.service knows which vt use
    $ systemctl --user start xorg@0.socket            # Start listening on the socket for display 0

これで X アプリケーションを実行すると仮想ターミナル2で自動的に xorg が起動します。

`XDG_VTNR` 環境変数は `.bash_profile` から systemd 環境に設定することができ、ウィンドウマネージャなど、あらゆる X アプリケーションを `xorg@0.socket` に依存する systemd ユニットとして起動することが可能です。

Warning: 現在、ユーザーサービスとしてウィンドウマネージャを実行するとセッションの外でウィンドウマネージャが実行されることになり次の問題が引き起こされます: セッションの破壊。ただし、systemd の開発者はウィンドウマネージャの実行を可能にする何かを作る予定があるようです。[3] や [4] を見て下さい。

## ユーザーユニットを書く

### サンプル

以下は mpd サービスのユーザーバージョンの例です。

    ~/.config/systemd/user/mpd.service

    [Unit]
    Description=Music Player Daemon

    [Service]
    ExecStart=/usr/bin/mpd --no-daemon

    [Install]
    WantedBy=default.target

### 変数を使用したサンプル

以下は `sickbeard.service` のユーザーバージョンの例で、SickBeard が特定のファイルを見つけられるようホームディレクトリの変数を使っています:

    ~/.config/systemd/user/sickbeard.service

    [Unit]
    Description=SickBeard Daemon

    [Service]
    ExecStart=/usr/bin/env python2 /opt/sickbeard/SickBeard.py --config %h/.sickbeard/config.ini --datadir %h/.sickbeard

    [Install]
    WantedBy=default.target

`man systemd.unit` に書かれているように、`%h` 変数はサービスを実行しているユーザーのホームディレクトリに置き換えられます。他にも systemd のマニュアルページで示されている変数が存在します。

### X アプリケーションについての注意

ほとんどの X アプリは実行するのに `DISPLAY` 変数を必要とします (あなたのサービスファイルが起動しない理由として第一に挙げられるでしょう)。systemd のユーザーインスタンスでこの変数を設定する方法は #DISPLAY を見て下さい。もしくは、以下のようにユニットでこの変数を設定することもできます:

    ~/.config/systemd/user/parcellite.service

    [Unit]
    Description=Parcellite clipboard manager

    [Service]
    ExecStart=/usr/bin/parcellite
    Environment=DISPLAY=:0

    [Install]
    WantedBy=mystuff.target

## ユースケース

### 永続的なターミナルマルチプレクサ

ウィンドウマネージャのセッションにログインする代わりに、ユーザーセッションでデフォルトで GNU Screen や Tmux などのターミナルマルチプレクサをバックグラウンドで実行したいということもあるでしょう。X ログインとログインを分割するのはディスプレイマネージャの代わりに TTY で起動したい場合にのみ有用です (その場合すべてを `myStuff.target` で起動するように記述できます)。

上述のようなタイプのユーザーセッションを作成するには、`wm.target` を作成する代わりに、`multiplexer.target` を作成します:

    [Unit]
    Description=Terminal multiplexer
    Documentation=info:screen man:screen(1) man:tmux(1)
    After=cruft.target
    Wants=cruft.target

    [Install]
    Alias=default.target

`cruft.target`, like `mystuff.target` above, should start anything you think should run before tmux or screen starts (or which you want started at boot regardless of timing), such as a GnuPG daemon session.

You then need to create a service for your multiplexer session. Here is a sample service, using tmux as an example and sourcing a gpg-agent session which wrote its information to `/tmp/gpg-agent-info`. This sample session, when you start X, will also be able to run X programs, since DISPLAY is set.

    [Unit]
    Description=tmux: A terminal multiplixer Documentation=man:tmux(1)
    After=gpg-agent.service
    Wants=gpg-agent.service

    [Service]
    Type=forking
    ExecStart=/usr/bin/tmux start
    ExecStop=/usr/bin/tmux kill-server
    Environment=DISPLAY=:0
    EnvironmentFile=/tmp/gpg-agent-info

    [Install]
    WantedBy=multiplexer.target

Once this is done, `systemctl --user enable` `tmux.service`, `multiplexer.target` and any services you created to be run by `cruft.target` and you should be set to go! Activated `user-session@.service` as described above, but be sure to remove the `Conflicts=getty@tty1.service` from `user-session@.service`, since your user session will not be taking over a TTY. Congratulations! You have a running terminal multiplexer and some other useful programs ready to start at boot!

### ウィンドウマネージャ

systemd のサービスとしてウィンドウマネージャを実行するには、まず Xorg を systemd のユーザーサービスとして実行する必要があります。以下では awesome を例として使います:

    ~/.config/systemd/user/awesome.service

    [Unit]
    Description=Awesome window manager
    After=xorg.target
    Requires=xorg.target

    [Service]
    ExecStart=/usr/bin/awesome
    Restart=always
    RestartSec=10

    [Install]
    WantedBy=wm.target

Note: The `[Install]` section includes a `WantedBy` part. When using `systemctl --user enable` it will link this as `~/.config/systemd/user/wm.target.wants/window_manager.service`, allowing it to be started at login. Is recommended to enable this service, not to link it manually.

## 参照

- KaiSforza's bitbucket wiki
- Zoqaeski's units on Github
- Collection of useful systemd user units
- Forum thread about changes in systemd 206 user instances

Categories:

- Daemons and system services (日本語)
- Boot process (日本語)