自宅GenAIを公開するけど、誰でも触れるのはちょっと怖いのでBasic認証をかけた話

背景 自宅で動かしている Ollama + GenAI モデル(例えば phi4:14b)を、インターネット越しに使いたくなった。OpenVPN で穴を開けた上で、Nginx を使って自宅マシンへのプロキシを構成。 [ インターネット ] ↓ VPSのnginx (443) ↓ OpenVPN経由のプライベートIP (100.64.x.x) ↓ 自宅のGenAIサーバ (Ollama) 確かに便利ではあるが、「誰でも使える状態」にしてしまうのは少し怖くなった。 なので、Basic認証 を導入して、ユーザーとパスワードを知らないとアクセスできないようにした。 Nginx に Basic認証を追加する手順 認証用パスワードファイルを作成する まず、htpasswd コマンドを使って .htpasswd を作成。 sudo apt install apache2-utils # 初回のみ sudo htpasswd -c /etc/nginx/.ollama_htpasswd user1 2. Nginx の設定に認証を追加 /etc/nginx/nginx.conf server { listen 443 ssl; server_name hoge.ingenboy.com; ssl_certificate /etc/letsencrypt/live/ollama.ingenboy.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ollama.ingenboy.com/privkey.pem; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept'; location / { # Basic 認証を有効にする auth_basic "Restricted Area"; auth_basic_user_file /etc/nginx/.ollama_htpasswd; proxy_pass http://100.64.1.41:11434; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } 3. 反映 sudo nginx -t && sudo systemctl reload nginx 4. 確認 curl -v https://ollama.ingenboy.com → 401 Unauthorized ...

May 6, 2025 · 1 min · 128 words · Me

Make back-up mechanism of self-hosted drive using Rsync and nginx

背景 自宅でfilebrowserというOSSを使ってwebからアクセス可能なドライブを作ったのですよ。 ただね、なんとこの間、5年間動かし続けた自作PCが壊れてしまい、直すまでドライブが使えないという問題が発生した。 Mean Time Between Failureをなるべく短くするために以下の二つの手段でドライブを冗長化する。 (しかも、リージョンが分かれているという。自宅で停電が発生しても、実家のドライブにアクセスするようになります。) filebrowserの下準備 メインのノードとは別にバックアップノードを用意しておき、rsyncで定期的にファイルを同期する filebrowserの前にnginxが動いているが、ここでHCを導入。メインがぶっ壊れた時にはバックアップにLBする。 0. filebrowserの下準備 Details filebrowserの立て方を簡単に教えますね。 バイナリをビルドするかダウンロードする(https://github.com/filebrowser/filebrowser) /usr/local/binに移動する。 パスワードとかゴニョゴニョする。パスワードのハッシュを生成。そして、–passwordの引数で渡す filebrowser hash mypassword ユニットファイルを作る。 例: [Unit] Description=FileBrowser Web UI After=network.target [Service] ExecStart=/usr/local/bin/filebrowser -a 0.0.0.0 -p 10001 -r /home/ray/hdd/filebrowser -d /etc/filebrowser/filebrowser.db --username hogehoge --password hogehoge --log /var/log/filebrowser.log WorkingDirectory=/etc/filebrowser Restart=always User=root Group=root [Install] WantedBy=multi-user.target sudo systemctl daemon-reload する sudo systemctl hogehogeが出力されたら、それを–passwordで渡す。 以上 1. rsyncで定期的にファイルを同期する 以下のコマンドを実行するcronジョブを作っておきましょう。毎時間ファイルを同期してくれます。 rsync -avz -e ssh ray@evn:~/hdd/filebrowser/ /opt/filebrowser_drive/ cronジョブの作り方は簡単 sudo crontab -e これで開いて、以下のジョブを登録する */1 * * * * rsync -avz -e "ssh -i /home/ray/.ssh/id_ed25519" ray@100.64.1.61:~/hdd/filebrowser/ /opt/filebrowser_drive/ cronはrootで実行されるので、鍵を指定しないと/home/root/.ssh の鍵を使いますが、めんどいので自分のを使うようにする。 ...

May 2, 2025 · 1 min · 186 words · Me

How_to_have_multiple_services_with_multiple_origin_on_a_single_frontend_proxy

事始め 会社ではL7プロキシの運用・開発をしている。 複数のEP(ドメイン)を持っている。 複数のドメインをひとつのL7プロキシ(単一のIP)でさばいている。 さて、これはいったいどの様に実現しているのか?というのが今回の議題。 IPアドレスはDNSによって単一のドメインと紐づけられる。と自分は認識していたが、これが誤りだった。 そして、自分は、会社に入るまでホストヘッダーという概念を全く分かっていなかった。 HTTPにはホストヘッダーというものがあり、これによって単一IP上に複数のドメインを保持することができるようになる。 そして、ポイントはやはり、HTTPはL7レイヤーであり、IPはL3レイヤーであるというところに落ち着くと思う。 前提 DNSでのIPアドレスとドメインの紐づけは一対一ではなく、一対多であった。ここがすごく大事なところでした。 そして、自分はホストヘッダーについて理解していなかった。 nginxを使ってバーチャルサーバを立てる chatgptから 単一の物理サーバー上で複数のウェブサイトやアプリケーションをホストするために使用される機能です。それぞれのバーチャルサーバーは、異なるドメイン名やサブドメインに対応して、個別に設定されたリソース(例えばウェブページやアプリケーションのファイル、SSL証明書、ログファイルなど)にアクセスを提供します。 Nginxでは、これらのバーチャルサーバーを「サーバーブロック」として設定ファイルに記述します。以下は、Nginxでのバーチャルサーバー設定の基本的な例です: server { listen 80; server_name example.com www.example.com; location / { root /var/www/example.com/html; index index.html index.htm; } error_page 404 /404.html; location = /404.html { root /var/www/example.com/html; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www/example.com/html; } } ホストヘッダーの役割 chatgptより HTTPのホストヘッダーは、HTTPリクエストを送信する際に非常に重要な役割を果たします。このヘッダーは、クライアントがリクエストを送信する際に、どのホスト(ドメイン名またはIPアドレス)とポートに対してリクエストが意図されているかを指定するために使用されます。特に、一つのサーバーが複数のドメインをホスティングしている場合(仮想ホスティング)、ホストヘッダーがないとサーバーはリクエストがどのウェブサイトに対してなのか判断できません。 HTTP/1.1ではホストヘッダーは必須とされています。これは、HTTP/1.0と異なり、サーバーが複数のドメインをホストしている状況が一般的になったためです。リクエストにホストヘッダーが含まれていない場合、サーバーは400 Bad Requestのエラーを返すことが多いです。 DNSのAレコード 複数のサブドメインが同じサーバーのリソースを指す場合、それら全てに同じIPアドレスを割り当てることが一般的です。 例えば、次のように設定することができます: www.example.com → 192.0.2.1 mail.example.com → 192.0.2.1 ftp.example.com → 192.0.2.1 これらのサブドメイン全てに同じAレコードのIPアドレス(192.0.2.1)を指定することで、一つのサーバーが異なるサービス(ウェブ、メール、FTPなど)を提供することができます。これは特に、ホスティングサービスが複数のウェブサイトを単一の物理サーバーで管理する場合などに便利です。また、メンテナンスやアップグレードが必要な場合にも、一箇所で変更を行うだけで済むため効率的です。 ...

December 31, 2024 · 1 min · 96 words · Me

RSA暗号、Opensslを使ったSSl証明書の発行、san証明書の発行方法、nginxでの設定方法

この記事の流れ opensslで秘密鍵を発行してみる 秘密鍵の中身を見る RSA暗号の解説。証明。 rsa暗号でサーバ証明書を発行するまで SAN付きのサーバ証明書の作り方 lets encryptでsan付きのサーバ証明書が作れるか そもそもsslサーバ証明書とは? 「サーバー証明書」とは、「通信の暗号化」「Webサイトの運営者・運営組織の実在証明」の2つの役割をもつ電子証明書です。 です。つまり、証明書には、暗号化用の鍵+証明書が入っている、ということになる。いいですね。 秘密鍵の中身をのぞいてみる。 秘密鍵の作成 $ sudo mkdir /etc/nginx/ssl $ sudo openssl genrsa -out /etc/nginx/ssl/server.key 512 秘密鍵を作っているけど、公開鍵はどこにあるのか??というのが非常に気になります。ていうか秘密鍵が因数分解されたものなんだっけ? だからいいのか。掛け算したら一瞬でわかるって話か。おけ。ってことでさ、適当に鍵を一つ作ってみたんだよ。 ちなみに、512bitより短い鍵は作れません。これすごいよね。 -----BEGIN PRIVATE KEY----- MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA4dNuxX/SzX3wEhde FmNFXLWlNkbGq4xaU6CfKy2nI9K+SWSKueJWSjoanmEG1eb6cXozmAk4eiuKm7zv +FdQowIDAQABAkB+1CdnRoXXIT7eej8+ZZyEGARkulVD7XyhcRlTv70aMWjC29cG 1LIeSScmy5ChqoGwH9Ow/BRzZXax3yeqMQFJAiEA9m+ardfTOK/xVoSn3I5pkzoR prW2xLQi0IDsv5lEu3UCIQDqlxAo6aDT0KpBBe5HbxBgw7uf34G+m7LJs/JnoMYQ twIgALXvr0KpFEfFnWdCiKtMeKU5Oc7aWRTf6NQGWsMZZKUCIFxk6wRyH9nNEYFS qKqR3818yeUJzrwX7q7qpMqT0+65AiEAqWRxDU6t8ZjPmJd6B7w481FuwrFmF9cq mq+QXX8gjRw= -----END PRIVATE KEY----- echo "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA4dNuxX/SzX3wEhde FmNFXLWlNkbGq4xaU6CfKy2nI9K+SWSKueJWSjoanmEG1eb6cXozmAk4eiuKm7zv +FdQowIDAQABAkB+1CdnRoXXIT7eej8+ZZyEGARkulVD7XyhcRlTv70aMWjC29cG 1LIeSScmy5ChqoGwH9Ow/BRzZXax3yeqMQFJAiEA9m+ardfTOK/xVoSn3I5pkzoR prW2xLQi0IDsv5lEu3UCIQDqlxAo6aDT0KpBBe5HbxBgw7uf34G+m7LJs/JnoMYQ twIgALXvr0KpFEfFnWdCiKtMeKU5Oc7aWRTf6NQGWsMZZKUCIFxk6wRyH9nNEYFS qKqR3818yeUJzrwX7q7qpMqT0+65AiEAqWRxDU6t8ZjPmJd6B7w481FuwrFmF9cq mq+QXX8gjRw=" | base64 --decode これでデコードしてもバイナリだからなんもわからんわ。 いかのスクリプトでデコードできるみたい。 from Crypto.PublicKey import RSA # Load the private key with open("private_key.pem", "r") as file: private_key = file.read() # Parse the private key key = RSA.import_key(private_key) # Extract the components n = key.n # Modulus e = key.e # Public exponent d = key.d # Private exponent p = key.p # Prime 1 q = key.q # Prime 2 print(f"Modulus (n): {n}") print(f"Public exponent (e): {e}") print(f"Private exponent (d): {d}") print(f"Prime 1 (p): {p}") print(f"Prime 2 (q): {q}") Modulus (n): 11827462552050103756019456673259686146276364164688350469602565108471900615793415256864500417710852720839063036792768824435280979352135219586691204539437219 Public exponent (e): 65537 Private exponent (d): 6642559381010851411383007183311248119169234719466623674178885422700539328402280041863549141435055457596044186231508711647457747564061370576607226853654857 Prime 1 (p): 111466148331411145531384799415569793304697439187343498431136600736302912289653 Prime 2 (q): 106108112006209210762976910352826494821357000184205525073929931397132009738423 ということですね。はい。 はい、でさ、RSA暗号の仕組みも今勉強してしまいましょうか。 ...

September 17, 2024 · 3 min · 619 words · Me