{"id":148626,"date":"2026-09-07T05:01:47","date_gmt":"2026-09-07T05:01:47","guid":{"rendered":"\/ca\/tutorials\/deploy-llm-with-vllm"},"modified":"2026-09-07T05:01:47","modified_gmt":"2026-09-07T05:01:47","slug":"deploy-llm-with-vllm","status":"publish","type":"post","link":"\/ca\/tutorials\/deploy-llm-with-vllm\/","title":{"rendered":"How to deploy an LLM with vLLM on a GPU server"},"content":{"rendered":"<p class=\"wp-block-paragraph\">To deploy an LLM with vLLM, <strong>prepare your GPU server and install vLLM there, then load your preferred vLLM-compatible model and serve it through an OpenAI-compatible API<\/strong>.<\/p><p class=\"wp-block-paragraph\">vLLM itself is a tool for running and serving LLMs on GPUs. It&rsquo;s designed for efficient model serving, especially when several requests need to share the same GPU.<\/p><p class=\"wp-block-paragraph\">Here&rsquo;s how to deploy an LLM with vLLM on your GPU server:<\/p><ol class=\"wp-block-list\">\n<li>Choose a GPU with enough VRAM for your model and expected workload.<\/li>\n\n\n\n<li>Connect to the GPU server over SSH and verify the NVIDIA hardware.<\/li>\n\n\n\n<li>Set up an isolated Python environment and install vLLM.<\/li>\n\n\n\n<li>Load the model and start its OpenAI-compatible API.<\/li>\n\n\n\n<li>Keep the vLLM server running with a systemd service.<\/li>\n\n\n\n<li>Protect remote API access with a private port and SSH tunnel.<\/li>\n\n\n\n<li>Send test requests and confirm the API key and network restrictions work.<\/li>\n\n\n\n<li>Compare inference throughput with single and concurrent requests.<\/li>\n<\/ol><p class=\"wp-block-paragraph\">This tutorial uses Qwen2.5-Coder-7B-Instruct as the vLLM model and Hostinger GPU as the provider. The overall process applies to other vLLM-compatible models and GPU providers, with slight differences in GPU sizing, server setup, and control-panel menus.<\/p><p class=\"wp-block-paragraph\"><\/p><h2 class=\"wp-block-heading\" id=\"h-1-choose-a-hostinger-gpu-for-the-model\">1. Choose a Hostinger GPU for the model<\/h2><p class=\"wp-block-paragraph\">Choose the L40S GPU with 48 GB of VRAM for the Qwen2.5-Coder-7B-Instruct model when you <a href=\"\/ca\/gpu-hosting\">rent a GPU<\/a> from Hostinger.<\/p><p class=\"wp-block-paragraph\">Your GPU for vLLM needs enough VRAM for the model weights, which depend on the parameter count and precision, plus the KV cache, runtime overhead, context length, and concurrent requests.<\/p><p class=\"wp-block-paragraph\">Start with the model weights because they set the baseline VRAM requirement. Use this simple estimate for a model with BF16 weights, such as <a href=\"https:\/\/huggingface.co\/Qwen\/Qwen2.5-Coder-7B-Instruct\" target=\"_blank\" rel=\"noopener\">Qwen2.5-Coder-7B-Instruct<\/a>:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">VRAM for model weights &asymp; parameter count &times; 2 bytes<\/pre><p class=\"wp-block-paragraph\">The model has 7.61 billion parameters, so the calculation is:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">7.61 billion &times; 2 bytes &asymp; 15.2 GB<\/pre><p class=\"wp-block-paragraph\">Don&rsquo;t treat <strong>15.2 GB<\/strong> as the model&rsquo;s total VRAM requirement, though.<\/p><p class=\"wp-block-paragraph\">You also need GPU memory for the CUDA runtime, activations that temporarily hold data while the model processes tokens, which stores previously processed token data for reuse during generation.<\/p><p class=\"wp-block-paragraph\">Hostinger offers the RTX 4090 with 24 GB of VRAM, starting at <strong>$0.38\/hour<\/strong>. That capacity exceeds the model&rsquo;s estimated 15.2 GB weight footprint.<\/p><p class=\"wp-block-paragraph\">However, we recommend the L40S, starting at <strong>$0.92\/hour<\/strong>, because its 48 GB of VRAM provides substantially more room for the KV cache, runtime overhead, longer context windows, and concurrent requests.<\/p><p class=\"wp-block-paragraph\">Use this comparison table to <a href=\"\/support\/how-to-choose-the-right-gpu-instance-at-hostinger\/\">choose the right Hostinger GPU<\/a> for your workload:<\/p><figure tabindex=\"0\" class=\"wp-block-table\"><table><tbody><tr><td><strong>GPU<\/strong><\/td><td><strong>VRAM<\/strong><\/td><td><strong>When to choose it<\/strong><\/td><\/tr><tr><td>RTX 4090<\/td><td>24 GB<\/td><td>Development, experimentation, and small- to medium-model inference<\/td><\/tr><tr><td><strong>L40S<\/strong><\/td><td><strong>48 GB<\/strong><\/td><td>AI inference and generative AI workloads (<strong>recommended for this deployment<\/strong>)<\/td><\/tr><tr><td>A100 80GB PCIe<\/td><td>80 GB<\/td><td>LLM inference with larger memory requirements, model training, and research workloads<\/td><\/tr><tr><td>RTX PRO 6000 (Server)<\/td><td>96 GB<\/td><td>Large-model inference and fine-tuning that require more VRAM than the L40S provides<\/td><\/tr><tr><td>B200<\/td><td>192 GB<\/td><td>Large-model fine-tuning, inference at scale, and other highly memory-intensive AI workloads<\/td><\/tr><tr><td>B200 (Dedicated)<\/td><td>192 GB<\/td><td>The same workloads as the B200 when you specifically need dedicated, non-shared GPU resources<\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">After choosing your GPU, <a href=\"\/support\/how-to-set-up-a-gpu-instance-at-hostinger\/\">set up your instance<\/a> in hPanel to choose your operating system, top up your account credits, and deploy it.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a70637\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a70637\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/hpanel-gpu-overview-l40s-instance-connection.png\/w=1024,h=1024,fit=scale-down\" alt=\"hPanel GPU overview showing L40S instance details and SSH connection information\" class=\"wp-image-156334\" title=\"hpanel-gpu-overview-l40s-instance-connection\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p><div class=\"announcement-block announcement-block--important\">\n            <span class=\"announcement-block__heading\">\n                <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                    <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n                          d=\"M12 22.5C17.799 22.5 22.5 17.799 22.5 12C22.5 6.20101 17.799 1.5 12 1.5C6.20101 1.5 1.5 6.20101 1.5 12C1.5 17.799 6.20101 22.5 12 22.5ZM13.637 7.65198C13.637 6.74791 12.9041 6.01501 12 6.01501C11.0959 6.01501 10.363 6.74791 10.363 7.65198C10.5335 9.53749 10.875 13.383 10.875 13.383C10.875 14.0043 11.3787 14.508 12 14.508C12.6213 14.508 13.125 14.0043 13.125 13.383V13.38L13.637 7.65198ZM11.9927 15.714C11.3714 15.714 10.8677 16.2177 10.8677 16.839C10.8677 17.4603 11.3714 17.964 11.9927 17.964H12.0073C12.6286 17.964 13.1323 17.4603 13.1323 16.839C13.1323 16.2177 12.6286 15.714 12.0073 15.714H11.9927Z\"\n                          fill=\"#FEA419\"\/>\n                <\/svg>\n                Important\n            <\/span>\n            <p class=\"announcement-block__content\">\n                <strong>Important!<\/strong> Hostinger GPU instances are billed hourly using your account credits. Hostinger destroys the instance and its data if your credits run out. Keep enough credits available while you use the server.\n            <\/p><\/div>\n\n\n\n<\/p><h2 class=\"wp-block-heading\" id=\"h-2-connect-to-the-gpu-server-and-verify-the-hardware\">2. Connect to the GPU server and verify the hardware<\/h2><p class=\"wp-block-paragraph\">Connect to your Hostinger GPU server over SSH and verify the L40S with <strong>nvidia-smi<\/strong> before installing vLLM.<\/p><p class=\"wp-block-paragraph\">In hPanel, go to <strong>Dev Tools &rarr; GPU &rarr; Manage<\/strong> and copy the SSH command from the <strong>Overview<\/strong> page:<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a746db\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a746db\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/hpanel-gpu-overview-ssh-command-highlighted.png\/w=1024,h=1024,fit=scale-down\" alt=\"hPanel GPU overview with the SSH command highlighted for the Qwen deployment\" class=\"wp-image-156335\" title=\"hpanel-gpu-overview-ssh-command-highlighted\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Then open a terminal on your computer, paste the command, and enter the root password to connect. Note the username and port in the SSH command &ndash; you&rsquo;ll need both later to open an SSH tunnel.<\/p><p class=\"wp-block-paragraph\">You can also <a href=\"\/ca\/tutorials\/how-to-setup-passwordless-ssh\/\">set up passwordless SSH<\/a> for more secure key-based access without entering the SSH password each time you log in.<\/p><p class=\"wp-block-paragraph\">Once connected, update the package list:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo apt update<\/pre><p class=\"wp-block-paragraph\">Next, verify the GPU:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">nvidia-smi<\/pre><p class=\"wp-block-paragraph\">The output should list the <strong>NVIDIA L40S<\/strong>, its driver version, the CUDA version supported by the driver, and about <strong>48 GB of GPU VRAM<\/strong>.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a78299\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a78299\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-nvidia-smi-l40s-gpu-idle.png\/w=1024,h=1024,fit=scale-down\" alt=\"Terminal output from nvidia-smi showing an NVIDIA L40S with available VRAM\" class=\"wp-image-156336\" title=\"terminal-nvidia-smi-l40s-gpu-idle\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Record the current VRAM usage so you can compare it with the usage after vLLM loads the Qwen2.5-Coder-7B-Instruct model.<\/p><h2 class=\"wp-block-heading\" id=\"h-3-install-vllm-in-a-python-environment\">3. Install vLLM in a Python environment<\/h2><p class=\"wp-block-paragraph\">To install vLLM in a Python environment, first set up the required tools, then use <strong>uv<\/strong> to create the environment and install the package.<\/p><p class=\"wp-block-paragraph\"><strong>uv<\/strong> downloads and manages the required Python version, so you don&rsquo;t need to install Python separately.<\/p><p class=\"wp-block-paragraph\">First, install <strong>curl <\/strong>and <strong>ninja-build<\/strong>, then use the former to install <strong>uv<\/strong>:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo apt install -y curl ninja-build\ncurl -LsSf https:\/\/astral.sh\/uv\/install.sh | sh\nsource \"$HOME\/.local\/bin\/env\"<\/pre><p class=\"wp-block-paragraph\">Next, create a directory for vLLM and move into it:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo mkdir -p \/opt\/vllm\nsudo chown \"$USER\":\"$USER\" \/opt\/vllm\ncd \/opt\/vllm<\/pre><p class=\"wp-block-paragraph\">Create and activate the <a href=\"\/ca\/tutorials\/how-to-create-a-python-virtual-environment\/\">Python virtual environment<\/a>:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">uv venv --python 3.12 --seed --managed-python\nsource .venv\/bin\/activate<\/pre><p class=\"wp-block-paragraph\">Now install the pinned vLLM version. Pinning the version keeps your setup reproducible and matches the commands in this tutorial.<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">uv pip install \"vllm==0.28.0\" --torch-backend=auto<\/pre><p class=\"wp-block-paragraph\">The <strong>&ndash;torch-backend=auto<\/strong> option selects a PyTorch build that matches your NVIDIA driver, so you don&rsquo;t need to choose a CUDA-specific package yourself.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a7c11c\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a7c11c\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-uv-install-vllm-0-28-0.png\/w=1024,h=1024,fit=scale-down\" alt=\"Terminal showing vLLM 0.28.0 installed with uv and the automatic PyTorch backend\" class=\"wp-image-156339\" title=\"terminal-uv-install-vllm-0-28-0\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Finally, verify the installation and confirm that PyTorch detects the L40S:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">python --version\nvllm --version\npython -c \"import torch; print('CUDA available:', torch.cuda.is_available()); print('GPU:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'none')\"<\/pre><p class=\"wp-block-paragraph\">The output should show <strong>Python 3.12<\/strong>, <strong>vLLM 0.28.0<\/strong>, <strong>CUDA available: True<\/strong>, and <strong>NVIDIA L40S<\/strong>.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a7f217\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a7f217\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-uv-install-vllm-0-28-0.png\/w=1024,h=1024,fit=scale-down\" alt=\"Terminal showing vLLM 0.28.0 installed with uv and the automatic PyTorch backend\" class=\"wp-image-156339\" title=\"terminal-vllm-installation-verification-l40s\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><h2 class=\"wp-block-heading\" id=\"h-4-serve-the-model-with-the-vllm-openai-compatible-api\">4. Serve the model with the vLLM OpenAI-compatible API<\/h2><p class=\"wp-block-paragraph\">Serve Qwen2.5-Coder-7B-Instruct with <strong>vllm serve<\/strong> to start an OpenAI-compatible API on the GPU server.<\/p><p class=\"wp-block-paragraph\">First, generate an API key:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">export VLLM_API_KEY=\"$(python -c 'import secrets; print(secrets.token_hex(32))')\"\necho \"$VLLM_API_KEY\"<\/pre><p class=\"wp-block-paragraph\">The first command generates the key and stores it as <strong>VLLM_API_KEY<\/strong>. The second prints the generated key, which looks similar to this:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">6f1c82e0b9d64cda829f5d707f5571590e98c42dd75a5204349fd9029e498865<\/pre><p class=\"wp-block-paragraph\">Save the printed key somewhere secure because you&rsquo;ll use the same value to connect to the API later.<\/p><p class=\"wp-block-paragraph\">Start the model and pass the API key to vLLM:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">vllm serve Qwen\/Qwen2.5-Coder-7B-Instruct \n   --host 127.0.0.1 \n   --port 8000 \n   --api-key \"$VLLM_API_KEY\"<\/pre><p class=\"wp-block-paragraph\">The <strong>&ndash;host 127.0.0.1<\/strong> option keeps vLLM accessible only from the GPU server, while <strong>&ndash;port 8000<\/strong> sets the local API port. The <strong>&ndash;api-key<\/strong> option requires clients to provide the key when sending requests to the OpenAI-compatible API endpoints.<\/p><p class=\"wp-block-paragraph\">The first launch takes a few minutes to an hour because vLLM needs to download and cache roughly 15 GB of model files. The exact time depends on your internet speed.<\/p><p class=\"wp-block-paragraph\">Wait until the terminal shows that the server has started successfully, then leave vLLM running in the current terminal.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a833d6\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a833d6\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-vllm-api-server-running.png\/w=1024,h=1024,fit=scale-down\" alt=\"vLLM terminal output showing the API server running on 127.0.0.1:8000\" class=\"wp-image-156341\" title=\"terminal-vllm-api-server-running\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Next, open a new terminal window, connect to the server the same way as before, and check the GPU again:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">nvidia-smi<\/pre><p class=\"wp-block-paragraph\">Compare the current VRAM usage with the value you noted before starting vLLM. The increase is expected because the loaded model, KV cache, and vLLM runtime all use GPU memory.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a87367\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a87367\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-nvidia-smi-vllm-model-vram-usage.png\/w=1024,h=1024,fit=scale-down\" alt=\"nvidia-smi output showing the loaded vLLM model using about 41 GB of L40S VRAM\" class=\"wp-image-156337\" title=\"terminal-nvidia-smi-vllm-model-vram-usage\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">You can now safely close this terminal.<\/p><h2 class=\"wp-block-heading\" id=\"h-5-keep-the-vllm-server-running-with-systemd\">5. Keep the vLLM server running with systemd<\/h2><p class=\"wp-block-paragraph\">Create a systemd service for vLLM so the server keeps running after you disconnect from your SSH session and restarts automatically after a failure.<\/p><p class=\"wp-block-paragraph\">Go to the terminal where you started vLLM and press <strong>Ctrl+C<\/strong> to stop it.<\/p><p class=\"wp-block-paragraph\">Save the API key in a file so systemd can use it after you close the terminal:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">printf 'VLLM_API_KEY=%sn' \"$VLLM_API_KEY\" | sudo tee \/etc\/vllm.env &gt; \/dev\/null\nsudo chmod 600 \/etc\/vllm.env<\/pre><p class=\"wp-block-paragraph\">You don&rsquo;t need to replace <strong>$VLLM_API_KEY<\/strong> with the actual key. The command takes the API key already saved in your terminal session and writes its value to <strong>\/etc\/vllm.env<\/strong>.<\/p><p class=\"wp-block-paragraph\">Next, create the systemd service:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo tee \/etc\/systemd\/system\/vllm.service &gt; \/dev\/null &lt;&lt;'EOF'\n[Unit]\nDescription=vLLM inference server\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nEnvironmentFile=\/etc\/vllm.env\nWorkingDirectory=\/opt\/vllm\nExecStart=\/opt\/vllm\/.venv\/bin\/vllm serve Qwen\/Qwen2.5-Coder-7B-Instruct --host 127.0.0.1 --port 8000\nRestart=on-failure\nRestartSec=5\n\n[Install]\nWantedBy=multi-user.target\nEOF<\/pre><p class=\"wp-block-paragraph\"><strong>Restart=on-failure<\/strong> starts vLLM again five seconds after the process exits with an error.<\/p><p class=\"wp-block-paragraph\">Reload systemd, start the service, and enable it to start automatically after a reboot:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo systemctl daemon-reload\nsudo systemctl enable --now vllm\nsudo systemctl status vllm --no-pager<\/pre><p class=\"wp-block-paragraph\">The status should show <strong>active (running)<\/strong>.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a8b355\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a8b355\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-systemctl-vllm-service-running.png\/w=1024,h=1024,fit=scale-down\" alt=\"systemctl status output showing the vLLM systemd service active and running\" class=\"wp-image-156338\" title=\"terminal-systemctl-vllm-service-running\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">vLLM still needs time to load the model and initialize its GPU components. Wait for a few minutes before checking anything.<\/p><p class=\"wp-block-paragraph\">Next, confirm that vLLM is serving requests after it finishes loading the cached model:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">source &lt;(sudo cat \/etc\/vllm.env)\n\ncurl -sS \n   -H \"Authorization: Bearer $VLLM_API_KEY\" \n   http:\/\/127.0.0.1:8000\/v1\/models<\/pre><p class=\"wp-block-paragraph\">The response should include <strong>Qwen\/Qwen2.5-Coder-7B-Instruct<\/strong>. You can now safely disconnect from SSH without stopping vLLM.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a8ecf5\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a8ecf5\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-vllm-api-model-list-response.png\/w=1024,h=1024,fit=scale-down\" alt=\"curl response listing Qwen2.5-Coder-7B-Instruct from the local vLLM API\" class=\"wp-image-156340\" title=\"terminal-vllm-api-model-list-response\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Check the service logs with this <a href=\"\/ca\/tutorials\/journalctl-command\/\">journalctl command<\/a> if <strong>systemctl status<\/strong> shows <strong>failed<\/strong> or vLLM doesn&rsquo;t respond after loading the model:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">journalctl -u vllm -n 100 --no-pager<\/pre><h2 class=\"wp-block-heading\" id=\"h-6-secure-access-to-the-vllm-api\">6. Secure access to the vLLM API<\/h2><p class=\"wp-block-paragraph\">Secure access to the vLLM API by keeping port <strong>8000<\/strong> private and connecting through an SSH tunnel.<\/p><p class=\"wp-block-paragraph\">Open a new terminal on your computer and run:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ssh -N -L 8000:127.0.0.1:8000 -p SSH_PORT ubuntu@GPU_IP_ADDRESS<\/pre><p class=\"wp-block-paragraph\">Replace <strong>SSH_PORT<\/strong> and <strong>GPU_IP_ADDRESS<\/strong> with the values shown for your GPU instance in hPanel.<\/p><p class=\"wp-block-paragraph\">After you authenticate, the terminal stays open without showing a shell prompt. This is expected because <strong>-N<\/strong> creates the SSH connection only for port forwarding.<\/p><p class=\"wp-block-paragraph\">Leave this terminal open while you use the vLLM API. The tunnel forwards <strong>http:\/\/127.0.0.1:8000<\/strong> on your computer to <strong>127.0.0.1:8000<\/strong> on the GPU server.<\/p><p class=\"wp-block-paragraph\">Note that Hostinger doesn&rsquo;t make non-SSH services publicly accessible by default, although you can <a href=\"\/support\/how-to-expose-a-service-on-your-hostinger-gpu-instance\/\">expose services on your GPU instance<\/a> through hPanel.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a92a92\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a92a92\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/hpanel-gpu-exposed-services-empty.png\/w=1024,h=1024,fit=scale-down\" alt=\"hPanel Exposed services page showing no public services configured for the GPU instance\" class=\"wp-image-156332\" title=\"hpanel-gpu-exposed-services-empty\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">However, avoid exposing any service using port <strong>8000<\/strong> because doing so makes the vLLM API reachable from the internet.<\/p><p class=\"wp-block-paragraph\">Also, <a href=\"\/support\/how-to-secure-exposed-services-on-your-hostinger-gpu-instance\/\">secure exposed services<\/a> with app authentication, firewall rules, and HTTPS certificates when you intentionally make a service public.<\/p><h2 class=\"wp-block-heading\" id=\"h-7-test-the-vllm-api-connection\">7. Test the vLLM API connection<\/h2><p class=\"wp-block-paragraph\">To test the vLLM API connection, send a chat request to your deployed model through the SSH tunnel, then verify that the API key is required and port <strong>8000<\/strong> isn&rsquo;t publicly accessible.<\/p><p class=\"wp-block-paragraph\">Open a new terminal on your computer. Then, load the API key you saved earlier:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">printf \"Paste the vLLM API key: \"\nread -s VLLM_API_KEY\necho\nexport VLLM_API_KEY<\/pre><p class=\"wp-block-paragraph\">Paste the key at the prompt. The terminal won&rsquo;t display it.<\/p><p class=\"wp-block-paragraph\">Next, send a request to the <strong>\/v1\/chat\/completions<\/strong> endpoint:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">curl -sS -w 'nHTTP %{http_code}n' \n   http:\/\/127.0.0.1:8000\/v1\/chat\/completions \n   -H \"Authorization: Bearer $VLLM_API_KEY\" \n   -H \"Content-Type: application\/json\" \n   -d '{\n   \"model\": \"Qwen\/Qwen2.5-Coder-7B-Instruct\",\n   \"messages\": [\n      {\n         \"role\": \"user\",\n         \"content\": \"Write a Python function named add(a, b) that returns a + b. Return code only.\"\n      }\n   ],\n   \"temperature\": 0,\n   \"max_tokens\": 64\n}'<\/pre><p class=\"wp-block-paragraph\">A successful request returns <strong>HTTP 200<\/strong>. The JSON response should show <strong>Qwen\/Qwen2.5-Coder-7B-Instruct<\/strong> in the <strong>model<\/strong> field, generated code in the response, and token counts under <strong>usage<\/strong>.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a9685f\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a9685f\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-vllm-chat-completion-http-200.png\/w=1024,h=1024,fit=scale-down\" alt=\"Terminal showing a successful vLLM chat completion request returning HTTP 200\" class=\"wp-image-156345\" title=\"terminal-vllm-chat-completion-http-200\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">After that, send a request without the <strong>Authorization<\/strong> header:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">curl -sS -o \/dev\/null -w 'HTTP %{http_code}n' \n&nbsp;&nbsp;&nbsp;http:\/\/127.0.0.1:8000\/v1\/models<\/pre><p class=\"wp-block-paragraph\">vLLM should return <strong>HTTP 401<\/strong>, confirming that it rejects requests without the API key.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a9a333\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a9a333\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-vllm-api-unauthorized-http-401.png\/w=1024,h=1024,fit=scale-down\" alt=\"Terminal showing an unauthenticated vLLM API request returning HTTP 401\" class=\"wp-image-156342\" title=\"terminal-vllm-api-unauthorized-http-401\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Finally, try connecting directly to port <strong>8000<\/strong> on the GPU instance instead of using the SSH tunnel:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">curl --connect-timeout 5 http:\/\/GPU_IP_ADDRESS:8000\/v1\/models<\/pre><p class=\"wp-block-paragraph\">The connection should time out or fail because vLLM listens on <strong>127.0.0.1<\/strong> and you haven&rsquo;t exposed port <strong>8000<\/strong>.<\/p><p class=\"wp-block-paragraph\">Also check your exposed services in hPanel and make sure none use internal port <strong>8000<\/strong>.<\/p><h2 class=\"wp-block-heading\" id=\"h-8-benchmark-inference-throughput\">8. Benchmark inference throughput<\/h2><p class=\"wp-block-paragraph\">Benchmark your vLLM throughput by comparing one request at a time with up to eight simultaneous requests.<\/p><p class=\"wp-block-paragraph\">Close the terminal you used for the API tests and stop the SSH tunnel with <strong>Ctrl+C<\/strong>.<\/p><p class=\"wp-block-paragraph\">Then start a new terminal, connect to your GPU server over SSH, activate the vLLM environment, and load the API key::<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">cd \/opt\/vllm\nsource .venv\/bin\/activate\nexport VLLM_API_KEY=\"$(sudo sed -n 's\/^VLLM_API_KEY=\/\/p' \/etc\/vllm.env)\"<\/pre><p class=\"wp-block-paragraph\">Next, run the benchmark with one request at a time:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">vllm bench serve \n   --backend openai-chat \n   --base-url http:\/\/127.0.0.1:8000 \n   --endpoint \/v1\/chat\/completions \n   --model Qwen\/Qwen2.5-Coder-7B-Instruct \n   --dataset-name random \n   --num-prompts 32 \n   --input-len 512 \n   --output-len 128 \n   --max-concurrency 1 \n   --header \"Authorization=Bearer ${VLLM_API_KEY}\" \n   --ignore-eos<\/pre><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469a9da9d\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469a9da9d\" class=\"aligncenter size-full wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-vllm-benchmark-concurrency-1.png\/public\" alt=\"vLLM benchmark results for 32 requests with maximum concurrency set to 1\" class=\"wp-image-156343\" title=\"terminal-vllm-benchmark-concurrency-1\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Run the same command again after the first benchmark finishes, but change <strong>&ndash;max-concurrency 1<\/strong> to <strong>&ndash;max-concurrency 8<\/strong>.<\/p><p class=\"wp-block-paragraph\">Keep the other settings unchanged. Both runs use <strong>32<\/strong> requests, <strong>512<\/strong> input tokens, and <strong>128<\/strong> output tokens, so concurrency is the only variable.<\/p><p class=\"wp-block-paragraph\">The <strong>&ndash;ignore-eos<\/strong> option makes each request generate the full <strong>128<\/strong> output tokens, which keeps the two runs comparable.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469aa146f\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469aa146f\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/terminal-vllm-benchmark-concurrency-8.png\/w=1024,h=1024,fit=scale-down\" alt=\"vLLM benchmark results for 32 requests with maximum concurrency set to 8\" class=\"wp-image-156344\" title=\"terminal-vllm-benchmark-concurrency-8\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">While running the benchmarks, check the <strong>Metrics<\/strong> section for your GPU instance in hPanel. Use the <strong>1h<\/strong> view to see the GPU compute throughput and VRAM usage during the tests.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469aa4dd7\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469aa4dd7\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/hpanel-gpu-metrics-compute-throughput-vram-usage.png\/w=1024,h=1024,fit=scale-down\" alt=\"hPanel GPU metrics showing compute throughput and VRAM usage during benchmarking\" class=\"wp-image-156333\" title=\"hpanel-gpu-metrics-compute-throughput-vram-usage\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Record the <strong>Request throughput (req\/s)<\/strong> and <strong>Output token throughput (tok\/s)<\/strong> values shown at the end of each benchmark. A completed comparison could look like this:<\/p><figure tabindex=\"0\" class=\"wp-block-table\"><table><tbody><tr><td><strong>Max concurrency<\/strong><\/td><td><strong>Request throughput (req\/s)<\/strong><\/td><td><strong>Output throughput (tok\/s)<\/strong><\/td><\/tr><tr><td>1<\/td><td>0.38<\/td><td>48.86<\/td><\/tr><tr><td>8<\/td><td>2.89<\/td><td>370.41<\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Request throughput shows how many requests vLLM completes per second, while output throughput shows how many output tokens it generates per second.<\/p><p class=\"wp-block-paragraph\">Increasing maximum concurrency from <strong>1<\/strong> to <strong>8<\/strong> raised request throughput from <strong>0.38<\/strong> to <strong>2.89 req\/s<\/strong> and output-token throughput from <strong>48.86<\/strong> to <strong>370.41 tok\/s<\/strong>.<\/p><h2 class=\"wp-block-heading\" id=\"h-how-vllm-handles-concurrent-inference-efficiently\">How vLLM handles concurrent inference efficiently<\/h2><p class=\"wp-block-paragraph\">vLLM handles concurrent inference efficiently with <strong>continuous batching, which keeps adding waiting requests as processing capacity becomes available, and PagedAttention, which reduces wasted KV-cache memory<\/strong>.<\/p><p class=\"wp-block-paragraph\">Unlike a fixed batch that waits for the whole group to finish, continuous batching lets vLLM start waiting requests while other requests are still generating tokens.<\/p><p class=\"wp-block-paragraph\">PagedAttention stores each request&rsquo;s KV cache, the attention data vLLM saves for previously processed tokens, in small blocks wherever VRAM is available. This reduces wasted gaps in GPU memory and leaves more room for concurrent requests.<\/p><h2 class=\"wp-block-heading\" id=\"h-when-to-use-vllm-instead-of-ollama\">When to use vLLM instead of Ollama<\/h2><p class=\"wp-block-paragraph\">Use vLLM instead of Ollama when <strong>you expect several users or apps to share the same GPU and serving more requests efficiently matters more than simplifying model setup<\/strong>.<\/p><p class=\"wp-block-paragraph\">The main difference is what each tool prioritizes. vLLM focuses on inference serving, with features such as continuous batching and PagedAttention, while <a href=\"\/ca\/tutorials\/what-is-ollama\/\">Ollama<\/a> simplifies downloading, running, and switching between models.<\/p><p class=\"wp-block-paragraph\">In practice, vLLM lets the GPU process concurrent requests more efficiently, but you configure more of the serving setup yourself. Ollama handles more of that setup for you, making it easier to get a model running quickly.<\/p><p class=\"wp-block-paragraph\">Choose vLLM for team coding assistants, application backends, shared internal tools, and other workloads that receive requests from several clients.<\/p><p class=\"wp-block-paragraph\"><a href=\"\/ca\/tutorials\/how-to-install-ollama\/\">Set up Ollama<\/a> for local development, trying different models, or personal tools where ease of use matters more than maximizing throughput.<\/p><p class=\"wp-block-paragraph\">For a simple AI-powered app sending only a few API requests at a time, either option works well.<\/p><h2 class=\"wp-block-heading\" id=\"h-how-to-connect-vllm-to-continue-in-vs-code\">How to connect vLLM to Continue in VS Code<\/h2><p class=\"wp-block-paragraph\">To connect vLLM to Continue in Visual Studio (VS) Code, <strong>configure Continue to send requests to http:\/\/127.0.0.1:8000\/v1 through your SSH tunnel<\/strong>.<\/p><p class=\"wp-block-paragraph\">Continue is an open-source AI coding assistant available as a VS Code extension. It supports OpenAI-compatible APIs, so you can use the Qwen model and API key you already configured.<\/p><h3 class=\"wp-block-heading\">Set up Continue with the vLLM endpoint<\/h3><p class=\"wp-block-paragraph\">Set up Continue by installing the VS Code extension, adding your vLLM API key as a local secret, and using <strong>http:\/\/127.0.0.1:8000\/v1<\/strong> as the API base URL.<\/p><ol class=\"wp-block-list\">\n<li>Open the extension marketplace in VS Code, search for <strong>Continue<\/strong>, and select <strong>Install<\/strong>.<\/li>\n<\/ol><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469aa8fd8\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469aa8fd8\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/vscode-extensions-continue-ai-coding-assistant.png\/w=1024,h=1024,fit=scale-down\" alt=\"VS Code Extensions Marketplace showing the Continue AI coding assistant extension\" class=\"wp-image-156349\" title=\"vscode-extensions-continue-ai-coding-assistant\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><ol start=\"2\" class=\"wp-block-list\">\n<li>Start the SSH tunnel and leave its terminal open:<\/li>\n<\/ol><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ssh -N -L 8000:127.0.0.1:8000 -p SSH_PORT ubuntu@GPU_IP_ADDRESS<\/pre><p class=\"wp-block-paragraph\">Replace <strong>SSH_PORT<\/strong> and <strong>GPU_IP_ADDRESS<\/strong> accordingly.<\/p><ol start=\"3\" class=\"wp-block-list\">\n<li>Open the <strong>Continue<\/strong> sidebar and go to <strong>Settings &rarr; Configs &rarr; Main Config<\/strong>. Click the gear icon to open <strong>config.yaml<\/strong>, which Continue creates automatically.<\/li>\n\n\n\n<li>Add the <strong>Qwen2.5-Coder-7B-Instruct<\/strong> model to <strong>config.yaml<\/strong>:<\/li>\n<\/ol><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">name: Self-hosted vLLM\nversion: 1.0.0\nschema: v1\n\nmodels:\n   - name: Qwen2.5 Coder 7B\n     provider: openai\n     model: Qwen\/Qwen2.5-Coder-7B-Instruct\n     apiBase: http:\/\/127.0.0.1:8000\/v1\n     apiKey: ${{ secrets.VLLM_API_KEY }}\n     roles:\n        - chat\n        - edit\n        - apply<\/pre><p class=\"wp-block-paragraph\">The <strong>provider: openai<\/strong> setting tells Continue to use the OpenAI-compatible API format. <strong>apiBase<\/strong> sends those requests to vLLM through the SSH tunnel.<\/p><p class=\"wp-block-paragraph\">Save <strong>config.yaml<\/strong> when you&rsquo;re done.<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469aacad0\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469aacad0\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/vscode-continue-config-yaml-vllm-qwen.png\/w=1024,h=1024,fit=scale-down\" alt=\"VS Code showing Continue config.yaml configured for the local vLLM Qwen endpoint\" class=\"wp-image-156347\" title=\"vscode-continue-config-yaml-vllm-qwen\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><ol start=\"5\" class=\"wp-block-list\">\n<li>In the same <strong>.continue<\/strong> folder as <strong>config.yaml<\/strong>, create a file named <strong>.env<\/strong> and add the vLLM API key you saved earlier:<\/li>\n<\/ol><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">VLLM_API_KEY=your-vllm-api-key<\/pre><p class=\"wp-block-paragraph\">Replace <strong>your-vllm-api-key<\/strong> with the actual key, then save <strong>.env<\/strong>.<\/p><ol start=\"6\" class=\"wp-block-list\">\n<li>Restart VS Code so Continue loads the API key from <strong>.env<\/strong>. Open Continue and select <strong>Qwen2.5 Coder 7B<\/strong> as the model.<\/li>\n<\/ol><h3 class=\"wp-block-heading\">Test the deployed model with a coding request<\/h3><p class=\"wp-block-paragraph\">To test the vLLM Continue integration, send a coding request from Continue while the SSH tunnel remains open.<\/p><p class=\"wp-block-paragraph\">For example, ask:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Write a Python function that checks whether a string is a palindrome and add three pytest tests.<\/pre><p class=\"wp-block-paragraph\">The exact response will vary, but a successful result should contain code similar to this:<\/p><div class=\"wp-block-image\"><figure data-wp-context='{\"imageId\":\"6a9e469ab14e6\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a9e469ab14e6\" class=\"aligncenter size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2026\/09\/image-5.png\/w=1024,h=1024,fit=scale-down\" alt=\"\" class=\"wp-image-156318\" title=\"vscode-continue-qwen-palindrome-code-response\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">This confirms that Continue reached your vLLM API through the SSH tunnel and received output from the configured model.<\/p><p class=\"wp-block-paragraph\">Repeat the <strong>curl<\/strong> API test you ran previously if Continue doesn&rsquo;t respond. Double-check the <strong>model<\/strong>, <strong>apiBase<\/strong>, and API key in your Continue configuration if <strong>curl<\/strong> works but Continue still can&rsquo;t connect.<\/p><h2 class=\"wp-block-heading\" id=\"h-next-steps-for-your-llm-deployment-with-vllm\">Next steps for your LLM deployment with vLLM<\/h2><p class=\"wp-block-paragraph\">Extend your LLM deployment with <strong>quantization to reduce VRAM usage, LoRA adapters to serve fine-tuned variants, or tensor parallelism to use multiple GPUs<\/strong>.<\/p><ul class=\"wp-block-list\">\n<li><strong>Quantization<\/strong>. It stores model weights at lower precision to reduce VRAM usage. Use it next when you want to fit a larger model on the same GPU or leave more memory available for inference. Serve a supported quantized model, such as an AWQ or GPTQ checkpoint.<\/li>\n\n\n\n<li><strong>LoRA adapters<\/strong>. They add small sets of fine-tuned weights to a base model without loading a separate copy of the full model. Use them next when you want to serve different specialized versions of the same base model. In vLLM, enable LoRA support with <strong>&ndash;enable-lora<\/strong> and load adapters with <strong>&ndash;lora-modules adapter-name=adapter-path<\/strong>.<\/li>\n\n\n\n<li><strong>Tensor parallelism<\/strong>. It splits a model across multiple GPUs. Use it next when the model no longer fits on one GPU or you want to spread its memory requirements across several GPUs. Set <strong>&ndash;tensor-parallel-size<\/strong> to the number of GPUs you want vLLM to use, for example, <strong>&ndash;tensor-parallel-size 2<\/strong> for two GPUs.<\/li>\n<\/ul><figure class=\"wp-block-image size-full\"><a class=\"hgr-tutorials-cta hgr-tutorials-cta-web-hosting\" href=\"\/ca\/web-hosting\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"300\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/2\/2023\/11\/Web-hosting_in-text-banner.png\/public\" alt=\"Hostinger web hosting banner\" class=\"wp-image-98604\"  sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>To deploy an LLM with vLLM, prepare your GPU server and install vLLM there, then load your preferred vLLM-compatible model and serve it through an OpenAI-compatible API. vLLM itself is a tool for running and serving LLMs on GPUs. It&rsquo;s designed for efficient model serving, especially when several requests need to share the same GPU. [&#8230;]<\/p>\n<p><a class=\"btn btn-secondary understrap-read-more-link\" href=\"\/ca\/tutorials\/deploy-llm-with-vllm\/\">Read More&#8230;<\/a><\/p>\n","protected":false},"author":411,"featured_media":148627,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"How to deploy an LLM with vLLM on a GPU server (%currentyear%)","rank_math_description":"Learn how to deploy an LLM with vLLM on a GPU server, secure API access, benchmark throughput, and connect the model to Continue in VS Code.","rank_math_focus_keyword":"deploy an LLM with vLLM","footnotes":""},"categories":[22720],"tags":[],"class_list":["post-148626","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hosting"],"hreflangs":[{"locale":"en-US","link":"https:\/\/www.hostinger.com\/tutorials\/deploy-llm-with-vllm","default":1},{"locale":"en-PH","link":"https:\/\/www.hostinger.com\/ph\/tutorials\/deploy-llm-with-vllm","default":0},{"locale":"en-MY","link":"https:\/\/www.hostinger.com\/my\/tutorials\/deploy-llm-with-vllm","default":0},{"locale":"en-GB","link":"https:\/\/www.hostinger.com\/uk\/tutorials\/deploy-llm-with-vllm","default":0},{"locale":"en-IN","link":"https:\/\/www.hostinger.com\/in\/tutorials\/deploy-llm-with-vllm","default":0},{"locale":"en-CA","link":"https:\/\/www.hostinger.com\/ca\/tutorials\/deploy-llm-with-vllm","default":0},{"locale":"en-AU","link":"https:\/\/www.hostinger.com\/au\/tutorials\/deploy-llm-with-vllm","default":0},{"locale":"en-NG","link":"https:\/\/www.hostinger.com\/ng\/tutorials\/deploy-llm-with-vllm","default":0}],"_links":{"self":[{"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/posts\/148626","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/users\/411"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/comments?post=148626"}],"version-history":[{"count":0,"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/posts\/148626\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/media\/148627"}],"wp:attachment":[{"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/media?parent=148626"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/categories?post=148626"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hostinger.com\/ca\/tutorials\/wp-json\/wp\/v2\/tags?post=148626"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}