1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

公式4GB推奨のOpen WebUIは1GB VPSで動く? さくらのAI Engineへ処理を逃がして検証した

1
Posted at

この記事は、Qiitaの「OpenAI・Anthropic互換APIを無料で使おう!『さくらのAI Engine』3,000リクエスト使い切りチャレンジ」参加記事です。

はじめに

さくらのAI Engineを試すなら、APIを直接叩くだけでなく、ChatGPTのようなUIから使いたくなります。そこで候補になるのが OpenWebUI です。OpenWebUIは、さまざまなAIモデルを、ChatGPT風の画面でまとめて使えるオープンソースのフロントエンドです。

OpenWebUIはPC上のDocker Engine上でホストすることも出来るのですが、常に立ち上げておくのが少しめんどくさいのと、自分一人しか使えない制限も出てしまうので、できればVPS上で利用したい。

さくらのナレッジブログでも、さくらのVPS上へOpenWebUIを構築する方法が解説されています。

ただ、公式案内では安定した利用にはメモリ4GB以上が推奨されています。

でも、「個人で試したいだけなら、お安い1GBプラン程度でも動かせないだろうか?」

そう考えて、さくらのVPS 1GBプランにOpen WebUIをDocker Composeで構築し、LLM部分の推論・Embedding・音声認識を可能な限りさくらのAI Engine側へ任せる構成を試してみました。

結論から言うと、今回の検証環境では1GBでも起動し、Open WebUIからさくらのAI Engineへチャットもできました

ただし、そのままでは動きませんでした。

特に効いたのは次の3点です。

  1. 2GBのswapを用意する
  2. Embeddingをローカルで処理させず、さくらのAI Engineへ送る
  3. SQLiteのメモリ使用量を低スペック環境向けに抑える

この記事では「なぜSwapなしの1GBでは厳しいのか」も確認しながら、最後にそのまま再現できる構築手順までまとめます。

💡 補足
本記事は「1GBでも動かせるか」という検証です。Open WebUI公式の推奨構成や、さくらインターネット公式の4GB以上という推奨を置き換えるものではありません。
少なくとも今回の環境では、1ユーザーでの検証用途として動作を確認しています。複数ユーザーでの簡易な負荷試験は行いましたが、多くの人に公開できるスケールはないことはご了承ください。


先に結果

今回の試行を先にまとめると、次のようになりました。

試したこと 結果
1GB / swapなしでOpen WebUIを起動 起動途中でメモリ不足になり、コンテナが再起動を繰り返した
swapを2GB追加 起動できるようになった
Open WebUI標準のローカルEmbedding 初回に約889MBのモデルがダウンロードされることを確認
EmbeddingをさくらのAI Engineへ変更 ローカルEmbeddingモデルを持たない構成にできた
STTをOpenAI互換APIへ変更 whisper-large-v3-turbo をさくらのAI Engineへ向ける構成にできた
SQLiteをデフォルトのまま使わない 低メモリ環境向けにpool / cache / mmapを明示的に制限
最終構成 1GB VPS上のOpen WebUIから、さくらのAI Engineへのチャットを確認

そこまで凝った設計というわけではないですが、それでも、「LLM推論さえ外部APIに出せば、WebUI側はほとんどメモリを使わない」というほど単純でもなかったです。

Open WebUIは単なるHTMLの画面ではありません。Pythonバックエンド、SQLite、Embedding、音声処理などを抱えているため、AIの推論を外へ出しても、UIサーバー自身のメモリ設計は必要でした。


今回の考え方:VPSを「AIサーバー」ではなく「AIへの窓口」にする

最終的な構成は次のとおりです。

[ブラウザ]
    │ HTTPS
    ▼
[さくらのVPS 1GB / Ubuntu 24.04]
    │
    ├─ Caddy
    │    └─ TLS終端 / リバースプロキシ
    │
    └─ Docker: Open WebUI (main-slim)
             │
             ├─ Chat Completions ──┐
             ├─ Embeddings ────────┼─ HTTPS ──> [さくらのAI Engine]
             └─ Speech-to-Text ────┘

ポイントは、VPS上でLLMを動かさないことです。

1GB VPSは「AIを計算するサーバー」ではなく、Open WebUIの画面・設定・データ保存を担当する薄いフロントエンドとして使います。

LLM推論だけでなく、ローカルでメモリを使いやすいEmbeddingやSTTも、OpenAI互換APIを通してさくらのAI Engineへ任せます。

さくらのAI Engineにはチャット生成に加え、Embeddingと音声文字起こしのAPIがあります。


検証環境

項目 内容
VPS さくらのVPS 1G(仮想2Core / メモリ1GB / SSD 50GB)
OS Ubuntu 24.04 amd64
Docker 29.1.3
Docker Compose 2.40.3
Open WebUI 0.11.0(main-slim
swap 2GB
リバースプロキシ Caddy

検証時のOpen WebUIイメージは以下でした。

ghcr.io/open-webui/open-webui:main-slim

後述しますが、main-slim は更新されるタグなので、同じ条件を再現したい場合はdigestで固定する方が確実です。


まず失敗:1GB・swapなしでは起動できなかった

最初はswapを作らず、そのままOpen WebUIを起動しました。

結果は、起動途中でメモリ不足になり、コンテナが再起動を繰り返す状態になりました。

1GBという物理メモリだけでは、少なくとも今回のOpen WebUI 0.11.0環境を安定して起動するには足りませんでした。

そこで、2GBのswapを追加します。

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

確認します。

swapon --show
free -h

例:

NAME      TYPE SIZE USED PRIO
/swapfile file   2G   0B   -2

/etc/fstab に追記しているのは、再起動後もswapを有効にするためです。

⚠️ 重要
「1GBなら常に2GB swapが必須」という意味ではありません。
今回の検証環境では、swapなしで起動に失敗し、2GBを追加した状態では起動できた、という実測結果です。


もう一つの罠:Embeddingモデルがローカルに降ってくる

Open WebUIのRAG機能は、Embeddingエンジンを指定しなければローカルのSentenceTransformersを利用できます。

低スペックVPSでは、これが問題になります。

今回の検証では、初回起動時にEmbedding用モデルとして約889MBのデータがダウンロードされました。

1GBメモリのVPSで、AI Engineという外部APIを使うためにOpen WebUIを立てているのに、VPS側へ約900MBのモデルを持たせるのは今回の目的と合いません。

そこでEmbeddingもOpenAI互換APIへ逃がします。

RAG_EMBEDDING_ENGINE: "openai"
RAG_OPENAI_API_BASE_URL: "https://api.ai.sakura.ad.jp/v1"
RAG_OPENAI_API_KEY: "${SAKURA_AI_API_KEY}"
RAG_EMBEDDING_MODEL: "multilingual-e5-large"

Open WebUI公式にも、RAG_EMBEDDING_ENGINE=openai でOpenAI互換Embedding APIを利用する設定があります。

さくらのAI Engine側では multilingual-e5-large のEmbedding APIが提供されています。

つまり、

「WebUIはVPS、ベクトル化はAI Engine」

という分担ができます。


SQLiteも低メモリ向けに調整する

ここは見落としやすいポイントでした。

Open WebUIはデフォルトでSQLiteを利用しますが、現在のOpen WebUI公式ドキュメントでは、低スペック環境向けに次の設定例が案内されています。

DATABASE_POOL_SIZE=8
DATABASE_SQLITE_PRAGMA_CACHE_SIZE=-2000
DATABASE_SQLITE_PRAGMA_MMAP_SIZE=0

公式ドキュメント:

Open WebUI公式は、低メモリ環境ではSQLiteのconnection pool、page cache、mmapを明示的に抑えることを勧めています。

今回の構成でも、その値を採用しました。

DATABASE_POOL_SIZE: "8"
DATABASE_SQLITE_PRAGMA_CACHE_SIZE: "-2000"
DATABASE_SQLITE_PRAGMA_MMAP_SIZE: "0"

これは「Open WebUIが重い=LLMが重い」というだけではないことを示すポイントでもあります。

LLMをAPI化しても、Webアプリ自身のDBやバックエンドが使うメモリは残るためです。


ここから構築手順

ここまでの考え方を踏まえて、実際に1GB VPSへ構築します。


Step 1. さくらのVPSを作成する

さくらのVPSのコントロールパネルからサーバーを作成します。

今回の設定は次のとおりです。

  • プラン: 1G
  • OS: Ubuntu 24.04 amd64
  • 公開鍵: 登録しておく
  • ログイン: 公開鍵認証を利用

「Setup and update」を使う場合

OSインストール時にスタートアップスクリプト「Setup and update」を使う場合、今回の構成では次のようにしました。

項目 今回の選択 理由
初回起動時にパッケージ更新 更新する セキュリティ更新を適用
ログインユーザー名 変更する 任意の管理ユーザーを利用
VM内部のファイアウォール 有効化 ufwを利用
swapfile 作成しない 後ほど2GBを手動作成
snap インストールしない 今回の構成では不要
Cockpit インストールしない 今回の構成では不要

パケットフィルタについて

さくらのVPSには、VM外側で動くパケットフィルタもあります。

本記事ではVM内部のufwを設定します。

外側のパケットフィルタも利用する場合は、少なくとも今回必要な次のポートが通るようにしてください。

  • 22/tcp: SSH
  • 80/tcp: HTTP / ACME
  • 443/tcp: HTTPS

後述するOpen WebUIの3000番ポートは、外部へ直接公開しません。


Step 2. SSHで接続する

作成したVPSへ公開鍵認証で接続します。

ssh <ユーザー名>@<サーバー名>.vs.sakura.ne.jp

さくらのVPSでは、標準で次の形式のホスト名が割り当てられます。

<サーバー名>.vs.sakura.ne.jp

今回の環境ではこのホスト名を公開DNSで名前解決できたため、後ほどCaddyのHTTPS化にもそのまま利用しました。独自ドメインは使用していません。

パスワード認証を使わない構成にした場合は、手元のPCから次のように確認できます。

ssh \
  -o PubkeyAuthentication=no \
  -o PreferredAuthentications=password \
  <ユーザー名>@<サーバー名>.vs.sakura.ne.jp

パスワード認証が無効なら、ログインは拒否されます。


Step 3. 2GBのswapを作る

前述のとおり、今回の1GB環境ではswapなしでOpen WebUIを起動できませんでした。

2GBのswapfileを作成します。

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

確認します。

swapon --show
free -h

Step 4. Docker / Docker Composeをインストールする

今回はUbuntuのパッケージを利用しました。

sudo apt update
sudo apt install -y docker.io docker-compose-v2

現在のユーザーをdockerグループへ追加します。

sudo usermod -aG docker "$USER"

グループ変更を反映するため、一度ログアウトしてSSH接続し直します。

再接続後に確認します。

docker --version
docker compose version
docker ps

docker pssudoなしで実行できれば、この先の手順をそのユーザーで進められます。

💡 補足
現在のCompose V2では、コマンドはdocker-composeではなく**docker compose**です。


Step 5. さくらのAI Engineのトークンを発行する

さくらのクラウドのコントロールパネルから、AI Engine用のアカウントトークンを発行します。

発行したトークンは、この後 .env に保存します。

⚠️ 注意
APIトークンは秘密情報です。スクリーンショットやQiitaの記事、Gitリポジトリに含めないよう注意してください。


Step 6. Open WebUIをDocker Composeで構築する

作業ディレクトリを作る

sudo mkdir -p /opt/open-webui
sudo chown "$USER":"$USER" /opt/open-webui

cd /opt/open-webui

.envを作る

APIトークンをcompose.yamlへ直接書かず、.envへ分離します。

cat > .env << 'EOF'
SAKURA_AI_API_KEY=<Step 5で取得したトークン>
WEBUI_SECRET_KEY=REPLACE_ME
EOF

sed -i "s/REPLACE_ME/$(openssl rand -hex 32)/" .env
chmod 600 .env

.envをGitで管理する可能性がある場合は、.gitignoreへ追加しておきます。

echo '.env' >> .gitignore

docker compose configの出力にも注意

Composeの設定を確認するときに、

docker compose config

を実行すると、環境変数が展開された結果が表示されます。

そのまま出力を記事やチャットへ貼ると、APIトークンを含めてしまう可能性があります。

設定ファイルの構造だけ確認したい場合は、今回の環境では次のようにしました。

docker compose config --no-interpolate

compose.yamlを作る

services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main-slim
    container_name: open-webui
    restart: unless-stopped

    ports:
      # Open WebUIをインターネットへ直接公開しない
      - "127.0.0.1:3000:8080"

    volumes:
      - open-webui-data:/app/backend/data

    environment:
      # --- さくらのAI Engine: Chat ---
      ENABLE_OPENAI_API: "true"
      ENABLE_OLLAMA_API: "false"
      OPENAI_API_BASE_URL: "https://api.ai.sakura.ad.jp/v1"
      OPENAI_API_KEY: "${SAKURA_AI_API_KEY}"

      WEBUI_SECRET_KEY: "${WEBUI_SECRET_KEY}"

      # --- さくらのAI Engine: Embedding / RAG ---
      RAG_EMBEDDING_ENGINE: "openai"
      RAG_OPENAI_API_BASE_URL: "https://api.ai.sakura.ad.jp/v1"
      RAG_OPENAI_API_KEY: "${SAKURA_AI_API_KEY}"
      RAG_EMBEDDING_MODEL: "multilingual-e5-large"

      # --- さくらのAI Engine: Speech-to-Text ---
      AUDIO_STT_ENGINE: "openai"
      AUDIO_STT_OPENAI_API_BASE_URL: "https://api.ai.sakura.ad.jp/v1"
      AUDIO_STT_OPENAI_API_KEY: "${SAKURA_AI_API_KEY}"
      AUDIO_STT_MODEL: "whisper-large-v3-turbo"

      # --- 低メモリ環境向けSQLite設定 ---
      DATABASE_POOL_SIZE: "8"
      DATABASE_SQLITE_PRAGMA_CACHE_SIZE: "-2000"
      DATABASE_SQLITE_PRAGMA_MMAP_SIZE: "0"

    # 今回の1GB検証環境で、ホスト全体を巻き込まないための安全弁
    mem_limit: 600m

    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  open-webui-data:

このComposeで重要な4点

1. ChatだけでなくEmbeddingもAI Engineへ送る

RAG_EMBEDDING_ENGINE: "openai"

を入れています。

これを入れずローカルEmbeddingを利用した際、今回の環境では約889MBのモデルダウンロードが発生しました。

1GB VPSでは無視しにくいサイズです。

さくらのAI EngineにはEmbedding APIがあるので、multilingual-e5-largeをそちらで利用します。


2. STTもOpenAI互換APIへ送る

Open WebUIにはOpenAI互換のSpeech-to-Text設定があります。

AUDIO_STT_ENGINE: "openai"
AUDIO_STT_OPENAI_API_BASE_URL: "https://api.ai.sakura.ad.jp/v1"
AUDIO_STT_MODEL: "whisper-large-v3-turbo"

さくらのAI Engineでも/v1/audio/transcriptionswhisper-large-v3-turboが提供されています。

Open WebUI側へWhisperを抱え込ませない構成にします。


3. SQLiteのメモリ使用量を制限する

DATABASE_POOL_SIZE: "8"
DATABASE_SQLITE_PRAGMA_CACHE_SIZE: "-2000"
DATABASE_SQLITE_PRAGMA_MMAP_SIZE: "0"

Open WebUI公式の低スペック環境向け設定を参考にしています。

💡 補足
Open WebUI公式ドキュメントでも、1GBはかなり厳しい条件として扱われています。
したがってこの設定は「1GBが推奨」という意味ではなく、制約の強い検証環境でどこまで削れるかという位置づけです。


4. 3000番ポートを外部公開しない

次の指定が地味ですが重要です。

ports:
  - "127.0.0.1:3000:8080"

例えば、

ports:
  - "3000:8080"

とすると、Dockerはホストのインターフェースへポートを公開します。

Linux上のDockerとufwには注意点があり、Docker公式ドキュメントにも、published portへの通信はufwのルールより前で処理され、ufwの設定が実質的に効かない場合があると説明されています。

そこで今回は、Open WebUIを127.0.0.1だけにbindし、外部からのアクセスはCaddyだけに通します。

Internet
   │
   ├─ 443 → Caddy → 127.0.0.1:3000 → Open WebUI
   │
   └─ 3000 → 外部公開しない

Open WebUIを起動する

docker compose up -d

状態を確認します。

docker compose ps

ログも確認します。

docker compose logs -f

ログの追跡を終了するときはCtrl+Cです。


再現性を上げたい場合:Dockerイメージをdigestで固定する

main-slimは更新されるタグなので、同じタグ名でも将来中身が変わる可能性があります。

検証環境を固定したい場合は、pullしたイメージのdigestを確認します。

docker compose pull
docker images --digests | grep open-webui

確認したdigestを指定します。

image: ghcr.io/open-webui/open-webui:main-slim@sha256:<確認したdigest>

今回の検証時はOpen WebUI 0.11.0で、次のdigestでした。

sha256:f67aea542a85e82cfab8c1de0719487b1566bffbb53c2b5448223611a16889dc

環境再現用の記録として残しておくと、後から「同じタグなのに挙動が違う」という問題を切り分けやすくなります。


Step 7. CaddyでHTTPS化する

Open WebUI自体は127.0.0.1:3000だけで待ち受けているため、そのままではインターネットからアクセスできません。

SSHポートフォワーディングを使えば暗号化されたトンネル経由でアクセスできますが、普段使いするたびにトンネルを張る必要があります。

そこで今回はCaddyをリバースプロキシとして置き、ブラウザからHTTPSでアクセスできるようにします。

ufwで80 / 443番を許可する

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status verbose

SSH接続にufwを利用している場合は、22/tcpが許可されていることも確認してください。


Caddyをインストールする

Caddy公式のDebian/Ubuntu向けリポジトリを登録します。

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo apt update
sudo apt install -y caddy

Caddyfileを設定する

sudo tee /etc/caddy/Caddyfile > /dev/null << 'EOF'
{
    email <実在するメールアドレス>
}

<サーバー名>.vs.sakura.ne.jp {
    reverse_proxy 127.0.0.1:3000
}
EOF

<実在するメールアドレス><サーバー名>を書き換えてください。

設定ファイルを検証します。

sudo caddy validate --config /etc/caddy/Caddyfile

問題がなければ、Caddyをgraceful reloadします。

sudo systemctl reload caddy

Caddy公式も、Caddyfile変更後はsystemctl reload caddyによる設定反映を案内しています。

ログを確認します。

sudo journalctl -u caddy --no-pager | tail -30

証明書取得に成功していれば、CaddyがHTTPSで待ち受けます。


Step 8. Open WebUIへアクセスする

ブラウザから次へアクセスします。

https://<サーバー名>.vs.sakura.ne.jp

初回ユーザーを作成します。

Open WebUIの設定によっては新規サインアップが有効になっている場合があるため、自分のアカウントを作成した後は管理画面で新規登録の設定を確認しておくことをおすすめします。

画面上部のモデル選択にさくらのAI Engine側のモデルが表示され、質問に対して応答が返れば、チャット接続は成功です。


メモリ使用量を確認する

VPS側で確認します。

free -h
docker stats --no-stream

1GB環境ではswapが利用されることがあります。

今回の構成では、**swapを使うこと自体を異常とみなさず、「物理メモリだけでは足りない瞬間を吸収するための余白」**として利用しています。

一方、swapが常時大量に読み書きされてレスポンスが悪化するようなら、1GBという構成自体が用途に合っていない可能性があります。

本番利用や複数ユーザー利用では、素直にメモリの多いプランを選ぶ方が安全です。


1GB化で効いたものを振り返る

今回の構成をもう一度整理します。

1. swapを用意した

今回の検証では、1GB・swapなしだとOpen WebUIが起動途中でメモリ不足になりました。

2GBのswapを追加して、起動時のピークを吸収しました。

2. EmbeddingをVPSに持たせなかった

ローカルEmbeddingを使ったときに約889MBのモデルがダウンロードされました。

これをさくらのAI Engineのmultilingual-e5-largeへ変更しました。

3. STTも外部APIへ向けた

音声文字起こしをOpen WebUI内のローカルWhisperに任せず、さくらのAI Engineのwhisper-large-v3-turboへ向けました。

4. SQLiteを低メモリ向けに調整した

Open WebUI公式の低スペック環境向け設定を参考に、connection pool、page cache、mmapを制限しました。

5. Dockerのポートをlocalhostだけにbindした

Open WebUIの3000番を直接インターネットへ公開せず、Caddy経由だけでアクセスする構成にしました。


やってみて分かったこと

当初は、

LLMの推論処理さえAI Engineへ出せば、Open WebUI側は1GBでも余裕なのでは?

と考えていました。

実際には、そこまで単純ではありませんでした。

Open WebUIには、

  • Webバックエンド
  • SQLite
  • Embedding
  • 音声処理
  • モデル一覧や設定の管理
  • ログや永続データ

といった、LLM推論以外の仕事があります。

つまり、外部AI APIを使う構成でも、

「AIの計算資源」と「AIを使うアプリケーションの計算資源」は別物

として考える必要があります。

今回の1GBチャレンジで一番面白かったのは、この境界が見えたことでした。

さくらのAI EngineのOpenAI互換APIを使うことで、Open WebUI側に重いモデルを置かず、

1GB VPS = AIを操作するための窓口

まで役割を絞れます。

一方で、その「窓口」にもDBやWebバックエンドを動かすための最低限のメモリは必要でした。


1GB VPSは実用的なのか?

今回確認できた範囲では、個人がAI Engineを試すための1ユーザー環境としてOpen WebUIを動かせました。

ただし、

  • 複数ユーザーの同時アクセス
  • 大量のRAGドキュメント
  • 高頻度なファイルアップロード
  • 長期間の運用
  • 高い可用性が必要な用途

までは検証していません。

また、Open WebUI公式ドキュメントでも1GB級のメモリは厳しい条件として扱われています。

そのため、

「1GBで動く」≠「1GBがおすすめ」

です。

今回は、キャンペーンの3,000リクエストを試したり、個人でOpenAI互換APIを触ったりするための最小構成チャレンジとして考えるのがよさそうです。


次に調べたいこと

今回の検証中には、まだ掘り下げたいテーマがいくつか残りました。

  • 約889MBダウンロードされたEmbeddingモデルの中身を追う
  • docker compose configから秘密情報を漏らさない方法を整理する
  • Dockerとufwの関係をパケットレベルでもう少し確認する
  • 1GB環境で何人まで同時に使えるか負荷試験する
  • Chat / Embedding / STTで、AI Engine側のリクエスト数がどう増えるか実測する

特に最後は、このキャンペーン名どおり3,000リクエストを本当に使い切るなら何をすると面白いか、という次の実験にもつながりそうです。


まとめ

公式では4GB以上が推奨されているOpen WebUIを、さくらのVPS 1GBプランで動かせるか試しました。

今回の検証環境では、次の工夫で起動・チャット接続まで確認できました。

  1. 2GBのswapを追加する
  2. EmbeddingをさくらのAI Engineへ逃がす
  3. STTもさくらのAI Engineへ向ける
  4. SQLiteを低メモリ向けに調整する
  5. Open WebUIはlocalhostだけで待ち受け、CaddyでHTTPS化する

単に「1GBでも動いた」というより、

AI Engineへ何を外部化でき、Open WebUI側には何が残るのか

を確認できたのが今回の収穫でした。

API互換性があると、単に既存コードを流用できるだけではありません。

重いAI処理をAPI側へ寄せ、手元や小さなVPSはUIやアプリケーションに徹するという構成を取りやすくなります。

最小VPSで試す場合の参考になれば幸いです。


参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?