sudo でルートに切り替えた瞬間、設定していたプロキシ変数が消えてパッケージ取得が失敗した——そんな経験のある運用担当者は多いはずです。Linuxではユーザーを切り替えると新しいログインシェルが起動し、元のシェル変数は原則として引き継がれません。この記事では環境変数を保持したまま別ユーザーとして作業する方法を、使用頻度の高い順に整理します。
なぜ切り替えると環境変数が消えるのか
Linuxのユーザー切り替えには「ログインシェルとして起動するか否か」という軸があります。sudo -i や su -(ハイフンあり)はログインシェルを起動するため、切り替え先ユーザーの ~/.bashrc や /etc/profile が読み込まれ、元の環境変数は上書きされます。ハイフンなしの su でも、sudo はデフォルトで env_reset が有効なためセキュリティ上の理由から多くの変数をリセットします。
特に影響を受けやすい変数は次のとおりです。
http_proxy/https_proxy— プロキシ環境下でのパッケージ取得・curl実行に影響PATH— カスタムパスが消え「コマンドが見つからない」が発生JAVA_HOME/GOPATHなど言語・ランタイム系の変数
sudo で環境変数を一時的に引き継ぐ
最も手軽な方法が sudo -E(--preserve-env)オプションです。現在のシェルの環境変数をそのまま保持してコマンドを実行します。
# 環境変数を保持して root でコマンドを実行する基本形
sudo -E コマンド名
# プロキシを引き継いで pip install を実行する例
sudo -E pip3 install requests
# root シェル自体を環境変数付きで起動する場合
sudo -E bash
特定の変数だけを渡したい場合は、コマンドの直前にインラインで指定するほうがスコープが明確で安全です。
# http_proxy だけを明示して渡す
sudo http_proxy="http://proxy.example.com:8080" apt-get update
注意:sudoers の設定によっては -E オプションが拒否される場合があります(!env_keep で明示除外されているケース)。その場合は次節の env_keep 設定が必要です。
sudoers で引き継ぐ変数をチームで統一する
プロキシ設定を常に引き継がせるなど、運用ポリシーとして固定したい場合は sudoers に env_keep を追記します。編集には必ず visudo を使い、直接 /etc/sudoers を vi で開かないでください。構文エラーがあると sudo が使用不能になります。
# visudo で安全に編集する(別端末で root セッションを維持してから作業すること)
sudo visudo
# /etc/sudoers に追記する内容(既存の Defaults 行の後ろに追加)
Defaults env_keep += "http_proxy https_proxy no_proxy"
Defaults env_keep += "JAVA_HOME GOPATH"
設定後は sudo env で対象変数が引き継がれているか確認します。
# sudo 実行後の環境変数を確認
sudo env | grep -E "proxy|JAVA_HOME|GOPATH"
/etc/sudoers.d/ 配下にファイルを分けて追記する方法も管理しやすくおすすめです。sudo visudo -f /etc/sudoers.d/env_keep で専用ファイルを作成できます。
su で環境変数を引き継ぐ
su コマンドで切り替える場合は --preserve-environment(短縮形 -p または -m)オプションを使います。
# 環境変数を保持して root に切り替える
su --preserve-environment
# 短縮形(-p / -m どちらでも同じ動作)
su -p
# 別ユーザーへの切り替え時も同様
su -p username
よくある誤りが su -p と su - を混同するケースです。su -(ハイフン単体)はログインシェルを起動するショートハンドで、-p と併用はできません。後に書いたオプションが優先されるため su - -p のように書くと -p が有効になりますが、意図がわかりにくくなるためどちらかに統一してください。
systemd サービスに環境変数を渡す
デーモンとして動作するサービスには、シェルの環境変数は一切引き継がれません。ある運用現場では「手元では動くのに systemd 経由だと失敗する」というトラブルの原因が、プロキシ変数が渡っていないことだったというケースが繰り返し報告されています。systemd サービスへは Environment= ディレクティブか EnvironmentFile= を使って渡します。
# /etc/systemd/system/myapp.service(抜粋)
[Service]
Environment="http_proxy=http://proxy.example.com:8080"
Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk"
# 複数変数は外部ファイルにまとめて読み込む方法も有効
EnvironmentFile=/etc/myapp/env
# ユニットファイル変更後は必ずリロードと再起動を行う
sudo systemctl daemon-reload
sudo systemctl restart myapp
# 変数が渡っているかログで確認
sudo journalctl -u myapp --since "5 minutes ago"
状況別の選び方と落とし穴
用途ごとの判断基準をまとめます。
- 1コマンドだけ引き継ぎたい:
sudo -E コマンドが最速。スコープが1コマンドに限定されるためセキュリティ面でも安全。 - root シェルで複数作業をしたい:
sudo -E bashで起動し、終わったら即exitする習慣をつける。 - チームで統一ルールを設けたい:
sudoersのenv_keepで変数を固定。個人の設定に依存しない運用になる。 - サービス・デーモンに渡したい:systemd の
Environment=が唯一の正規手段。シェルの設定は届かない。
実務でよく遭遇する失敗として、sudo -E を使ったにもかかわらず変数が消えるケースがあります。sudo -V を実行すると現在のセキュリティポリシーが表示され、Env. var. file や env_keep の状態を確認できます。env_reset が有効で env_keep に対象変数が含まれていなければ、前節の sudoers 設定で解決できます。
もう一点注意が必要なのが PATH の引き継ぎです。ユーザーが独自に追加したパスを含む PATH を root に引き継ぐと、そのパスに悪意のあるバイナリが仕込まれていた場合に root 権限で実行されるリスクがあります。自動化スクリプトや CI 環境では PATH を env_keep に含めず、実行するコマンドを絶対パスで指定するほうが安全です。
「コマンドは打てる。次は”現場で通用する型”を最短で身につけたい」——そんなあなたへ。
ネットの断片的なTipsをコピペするだけでは、体系的な運用スキルはなかなか積み上がりません。リナックスマスター.JPの無料メルマガ「リナマガ」では、現場で実際に使うLinuxサーバー運用の考え方を、順を追って実務目線でお届けしています。いま登録された方には、安全なサーバー構築の「型」をまとめた『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼント中です。
>> 図解60P『Linux入門マニュアル』を無料で受け取る
(メルマガ登録は10秒・いつでも解除OK)
※ 「独学の時間がもったいない」「プロから現場の技術を最短で学びたい」という本気の方には、2日で実務レベルが身につく初心者向けハンズオンセミナーもご用意しています。
