How to Use Vim on a Linux VPS
A practical Vim tutorial built around real server administration tasks. Learn modes, navigation, editing, search and replace, splits, .vimrc configuration, and workflows for editing Nginx, SSH, and Docker Compose files over SSH.
Vim is the default text editor on most Linux servers. When you SSH into a VPS to edit an Nginx config, change an SSH port, or tweak a Docker Compose file, Vim is what you get. This tutorial teaches Vim through real server administration tasks instead of abstract examples.
You will learn how Vim modes work, how to navigate and edit files efficiently, how to search and replace text, how to work with multiple files using splits and buffers, and how to set up a .vimrc that makes server work faster.
Prerequisites: A Linux VPS (Debian or Ubuntu) with SSH access Linux VPS Security: Threats, Layers, and Hardening Guide. Basic terminal familiarity (running commands, navigating directories).
How do I install Vim on Ubuntu or Debian?
Most Debian and Ubuntu servers ship with vim-tiny, a stripped-down build that lacks syntax highlighting, undo history, and plugin support. Install the full version to get all features covered in this tutorial.
sudo apt update && sudo apt install vim -y
Verify the installation:
vim --version | head -1
Expected output on Debian 12 (Bookworm):
VIM - Vi IMproved 9.0 (2022 Jun 28, compiled Nov 15 2023 17:28:07)
On Ubuntu 24.04 LTS, you will see Vim 9.1. The exact patch version varies by distribution, but all features in this tutorial work on Vim 8.2 and later.
What about Neovim? Neovim is a fork of Vim with a Lua-based config system and built-in LSP support. Everything in this tutorial applies to Neovim except the .vimrc path (Neovim uses ~/.config/nvim/init.vim). If you prefer Neovim, install it with sudo apt install neovim.
Start the built-in tutorial
Vim ships with an interactive tutorial that takes about 30 minutes. Run it before reading further if you have never used Vim:
vimtutor
This opens a practice file where you learn by doing. It covers the basics of movement and editing. The rest of this article goes deeper and adds server-specific workflows that vimtutor does not cover.
What are Vim modes and how do they work?
Vim has four main modes. Normal mode is the default. You use it for navigation and running commands. Insert mode is for typing text, entered with i. Visual mode selects text, entered with v. Command-line mode runs commands like save and quit, entered with :. Press Esc to return to normal mode from any other mode.
This is different from editors like nano where you type immediately. In Vim, keystrokes in normal mode are commands, not characters. This is called modal editing.
| Mode | Enter with | Purpose | Return to Normal |
|---|---|---|---|
| Normal | Esc (or open a file) |
Navigate, delete, copy, paste, run commands | Already in normal mode |
| Insert | i, a, o, I, A, O |
Type and edit text | Esc |
| Visual | v (char), V (line), Ctrl+v (block) |
Select text for operations | Esc |
| Command-line | : |
Run ex commands (save, quit, search, replace) | Enter or Esc |
The mode indicator appears at the bottom left of the screen. When you see -- INSERT --, you are in insert mode. When nothing is shown, you are in normal mode.
If you feel stuck: press Esc two or three times. This always returns you to normal mode regardless of your current state.
How do I navigate files in Vim?
Navigation in Vim happens in normal mode. The basic movement keys are h (left), j (down), k (up), and l (right). Arrow keys also work, but hjkl keeps your fingers on the home row and is faster once you build muscle memory.
Character and line movement
| Key | Action |
|---|---|
h |
Move left one character |
j |
Move down one line |
k |
Move up one line |
l |
Move right one character |
0 |
Jump to start of line |
$ |
Jump to end of line |
^ |
Jump to first non-blank character |
Word movement
| Key | Action |
|---|---|
w |
Jump to start of next word |
b |
Jump back to start of previous word |
e |
Jump to end of current word |
W |
Jump to next WORD (whitespace-delimited) |
B |
Jump back to previous WORD |
File movement
| Key | Action |
|---|---|
gg |
Go to first line of file |
G |
Go to last line of file |
42G or :42 |
Go to line 42 |
Ctrl+d |
Scroll down half a page |
Ctrl+u |
Scroll up half a page |
Ctrl+f |
Scroll down one full page |
Ctrl+b |
Scroll up one full page |
% |
Jump to matching bracket ((, {, [) |
Search navigation
Press / to search forward, then type your search term and press Enter. Press n to jump to the next match and N to jump to the previous match. Press ? to search backward.
Example: you are editing /etc/nginx/nginx.conf and need to find the worker_connections directive:
/worker_connections
Vim jumps to the first match. Press n to cycle through all matches in the file.
How do I edit text in Vim?
Editing in Vim follows a pattern: operator + motion. The operator says what to do (delete, change, yank). The motion says what text to act on (word, line, paragraph). This composability is what makes Vim fast once you internalize a few building blocks.
Entering insert mode
| Key | Action |
|---|---|
i |
Insert before cursor |
a |
Append after cursor |
I |
Insert at beginning of line |
A |
Append at end of line |
o |
Open new line below and enter insert mode |
O |
Open new line above and enter insert mode |
Delete, change, yank, and put
| Command | Action |
|---|---|
x |
Delete character under cursor |
dd |
Delete entire line |
dw |
Delete from cursor to start of next word |
d$ or D |
Delete from cursor to end of line |
cc |
Change entire line (deletes and enters insert mode) |
cw |
Change word (deletes word and enters insert mode) |
ci" |
Change inside quotes (deletes text between " and enters insert mode) |
yy |
Yank (copy) entire line |
yw |
Yank word |
p |
Put (paste) after cursor |
P |
Put before cursor |
Undo and redo
| Key | Action |
|---|---|
u |
Undo last change |
Ctrl+r |
Redo (undo the undo) |
. |
Repeat last change |
The . (dot) command is one of Vim's most useful features. It repeats whatever you last did. Change a word with cw, type the replacement, press Esc. Now move to another word and press . to make the same change.
Server-relevant editing examples
Delete a directive from an Nginx config:
Position your cursor on the line access_log /var/log/nginx/access.log; and press dd to delete the entire line.
Change a port number in quotes:
Position your cursor anywhere inside "8080" in a Docker Compose file and press ci". This deletes 8080 and puts you in insert mode. Type 3000 and press Esc.
Delete two words from a directive:
Press d2w to delete the next two words from the cursor position. Vim commands accept a count before the motion: 3dd deletes three lines, 5j moves down five lines.
How do I search and replace text in Vim?
Use :s (substitute) to replace text. The basic syntax is :s/old/new/flags. This command works on the current line by default. Use :%s to apply it to the entire file.
Substitute patterns
| Command | Action |
|---|---|
:s/foo/bar/ |
Replace first foo with bar on current line |
:s/foo/bar/g |
Replace all foo with bar on current line |
:%s/foo/bar/g |
Replace all foo with bar in entire file |
:%s/foo/bar/gc |
Replace all with confirmation (y/n for each match) |
:5,10s/foo/bar/g |
Replace all on lines 5 through 10 |
Practical examples
Change the Nginx listen port from 80 to 443:
:%s/listen 80;/listen 443 ssl;/g
Comment out a line in sshd_config:
Move to the line and press I to insert at the beginning, type #, press Esc.
Comment out multiple lines: Select lines with V (visual line mode), move down with j to extend the selection, then type :s/^/#/ and press Enter. This prepends # to each selected line.
Replace a Docker image tag:
:%s/nginx:1.24/nginx:1.27/g
Regex basics in Vim substitute
Vim uses its own regex flavor. A few patterns you will use often on server configs:
| Pattern | Matches |
|---|---|
^ |
Start of line |
$ |
End of line |
. |
Any single character |
\d |
A digit (0-9) |
.* |
Any characters (greedy) |
\s |
Whitespace |
To match literal dots (like in IP addresses), escape them: :%s/192\.168\.1\.1/10.0.0.1/g.
How do I edit multiple files in Vim with splits and buffers?
Vim can open multiple files in a single session using buffers, split windows, and tabs. This is useful when you need to cross-reference files while editing, like checking nginx.conf while editing a site-specific server block.
Buffers
A buffer is a file loaded into memory. You can have many buffers open and switch between them.
| Command | Action |
|---|---|
:e /etc/nginx/sites-available/default |
Open file in new buffer |
:bn |
Switch to next buffer |
:bp |
Switch to previous buffer |
:ls |
List all open buffers |
:b2 |
Switch to buffer number 2 |
:bd |
Close current buffer |
Split windows
Splits let you see two files side by side in the same terminal.
| Command | Action |
|---|---|
:sp /path/to/file |
Horizontal split (top/bottom) |
:vs /path/to/file |
Vertical split (left/right) |
Ctrl+w h/j/k/l |
Move between splits (left/down/up/right) |
Ctrl+w = |
Make all splits equal size |
Ctrl+w q |
Close current split |
Example workflow: edit a Docker Compose file while referencing the .env file:
:e docker-compose.yml
:vs .env
You now have two panes. Use Ctrl+w l and Ctrl+w h to switch between them.
Tabs
Tabs are collections of windows. Most people find splits sufficient for server work, but tabs are available:
| Command | Action |
|---|---|
:tabnew /path/to/file |
Open file in new tab |
gt |
Go to next tab |
gT |
Go to previous tab |
:tabclose |
Close current tab |
How do I customize Vim with a .vimrc file?
The .vimrc file in your home directory controls Vim's behavior. Without it, Vim runs in a near-compatible Vi mode that lacks many features. A good .vimrc tuned for server work makes editing config files faster.
Create or edit your .vimrc:
vim ~/.vimrc
Add these settings. Each line has a comment explaining what it does:
" Disable Vi compatibility mode (enable all Vim features)
set nocompatible
" Use UTF-8 encoding (required for special characters in listchars on minimal server images)
set encoding=utf-8
" Show line numbers (essential for config files with error messages referencing line numbers)
set number
" Show relative line numbers (makes jumping N lines easy: 5j, 12k)
set relativenumber
" Enable syntax highlighting
syntax on
" Use spaces instead of tabs (most config files expect spaces)
set expandtab
" Set tab width to 2 spaces (common for YAML, Nginx configs)
set tabstop=2
set shiftwidth=2
set softtabstop=2
" Highlight search results as you type
set incsearch
set hlsearch
" Case-insensitive search unless uppercase is used
set ignorecase
set smartcase
" Show matching brackets
set showmatch
" Always show the status line (shows filename and position)
set laststatus=2
" Enable mouse support (useful in modern terminals)
set mouse=a
" Show current mode in status line
set showmode
" Set pastetoggle to F2 (toggle paste mode for clean pasting over SSH)
set pastetoggle=<F2>
" Disable swap files (avoids .swp clutter on servers)
set noswapfile
" Enable filetype detection (loads correct indentation for yaml, json, etc.)
filetype plugin indent on
" Highlight the current line
set cursorline
" Show whitespace characters (catch trailing spaces and mixed indentation)
set list
set listchars=tab:»·,trail:·
Save and exit with :wq. The settings take effect the next time you open Vim.
To reload your .vimrc without restarting Vim:
:source ~/.vimrc
Paste mode for SSH sessions
When you paste text from your local clipboard into Vim over SSH, auto-indentation can create a cascading indent effect where each line shifts further right. This happens because Vim treats pasted text as typed input and applies indent rules to each line.
Toggle paste mode before pasting:
- Press
F2(if you setpastetoggleas shown above) or type:set paste - Enter insert mode with
i - Paste your text (Ctrl+Shift+V or right-click in your terminal)
- Press
F2again or type:set nopaste
Modern terminals with Vim 8.2+ support bracketed paste mode, which handles this automatically. If you use a recent terminal emulator (kitty, Alacritty, WezTerm, recent GNOME Terminal), paste mode toggling may not be necessary.
How do I add plugins with vim-plug?
vim-plug is a lightweight plugin manager that installs plugins in parallel. It requires a single file download and a few lines in your .vimrc.
Install vim-plug
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
Verify the file exists:
ls -la ~/.vim/autoload/plug.vim
You should see the file with your user ownership.
Configure plugins in .vimrc
Add a plugin block to the top of your ~/.vimrc, before the settings:
call plug#begin('~/.vim/plugged')
" File explorer sidebar
Plug 'preservim/nerdtree'
" Fuzzy file finder
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
" Git status indicators in the gutter
Plug 'airblade/vim-gitgutter'
call plug#end()
Save the file, then install the plugins:
:source ~/.vimrc
:PlugInstall
vim-plug downloads each plugin in parallel. After installation, you can open NERDTree with :NERDTree, use :Files to fuzzy-find files, and see git diff markers in the gutter.
Keep it minimal on servers. Plugins add startup time. On a VPS where you edit config files occasionally, three to five plugins is plenty. Save heavier setups for your local development machine.
How do I edit server config files with Vim over SSH?
This section covers workflows you will use repeatedly when managing a VPS. Each example uses a real file and shows the exact steps.
Use sudoedit instead of sudo vim
When editing root-owned files like /etc/nginx/nginx.conf or /etc/ssh/sshd_config, use sudoedit instead of sudo vim.
sudoedit /etc/nginx/nginx.conf
sudoedit copies the file to a temporary location, opens it with your user's Vim (including your .vimrc settings and plugins), then copies it back with root permissions when you save and quit. This is safer than sudo vim for two reasons:
sudo vimruns Vim as root. Any Vim command like:!bashspawns a root shell. On multi-user servers this is a privilege escalation risk.sudoeditpreserves your user environment. You get your syntax highlighting, line numbers, and keybindings.
Edit an Nginx server block
Open the default site configuration:
sudoedit /etc/nginx/sites-available/default
Find the server_name directive by typing /server_name and pressing Enter. Vim jumps to the match. Press cw to change the word after the directive, type your domain, press Esc.
After saving, verify the Nginx config syntax:
sudo nginx -t
Expected output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Then reload:
sudo systemctl reload nginx
Change the SSH port in sshd_config
sudoedit /etc/ssh/sshd_config
Search for the port directive:
/^#\?Port
This regex matches both Port and #Port (commented out). If the line is commented, press 0 to go to the start of the line, press x to delete the #, then press f followed by a space to jump to the space before the port number. Press cw, type the new port number (for example 2222), and press Esc.
Verify the config:
sudo sshd -t
No output means the syntax is valid. Restart the service:
sudo systemctl restart sshd
Before disconnecting, open a second SSH session on the new port to verify you can still connect. Losing SSH access by changing the port without testing is a common mistake Linux VPS Security: Threats, Layers, and Hardening Guide.
Edit a Docker Compose file
vim ~/myapp/docker-compose.yml
YAML files are indentation-sensitive. The .vimrc settings from earlier (2-space tabs, expandtab) handle this correctly. If you see tab characters in a YAML file, convert them:
:%s/\t/ /g
This replaces all tabs with two spaces. Save and validate the file:
docker compose config --quiet
No output means the YAML is valid. If there is a syntax error, Docker Compose prints the line number. Jump directly to that line in Vim with vim +42 docker-compose.yml (where 42 is the error line).
Edit a systemd unit file
sudoedit /etc/systemd/system/myapp.service
After saving changes to a systemd unit, reload the daemon:
sudo systemctl daemon-reload
Then restart the service and verify:
sudo systemctl restart myapp
sudo systemctl status myapp
Sharp eyes: check the Active: line in the status output. It should show active (running). If it shows failed, read the logs:
journalctl -u myapp -n 20 --no-pager
Vim survival cheatsheet
The ten commands you need on day one:
| Command | Action |
|---|---|
i |
Enter insert mode |
Esc |
Return to normal mode |
:wq |
Save and quit |
:q! |
Quit without saving |
dd |
Delete line |
u |
Undo |
/text |
Search forward |
:%s/old/new/g |
Replace all in file |
:sp file |
Split window |
F2 |
Toggle paste mode |
For the complete reference with navigation, editing, visual mode, buffers, splits, regex patterns, and server workflow shortcuts, see Vim Cheatsheet.
Something went wrong?
Vim opened and I cannot type. You are in normal mode. Press i to enter insert mode.
I see -- INSERT -- but my keystrokes do weird things. You may have accidentally pressed Ctrl+s, which freezes terminal output. Press Ctrl+q to unfreeze.
My pasted text has staircase indentation. Toggle paste mode with F2 or :set paste before pasting. Remember to turn it off after: F2 again or :set nopaste.
Vim says "E45: 'readonly' option is set." The file is read-only. Quit with :q and reopen with sudoedit /path/to/file.
I made a mistake and saved. If the file is a system config, Vim may have left a backup. Check for filename~ in the same directory. You can also undo after reopening if you set set undofile and set undodir=~/.vim/undodir in your .vimrc (create the directory first with mkdir -p ~/.vim/undodir).
Swap file warning: ".file.swp" already exists. A previous Vim session crashed or is still open. If no other session is editing the file, choose (D)elete to remove the swap file. If you disabled swap files in your .vimrc (set noswapfile), this will not happen.
Next steps: Pair Vim with a terminal multiplexer so your editing sessions survive disconnections. See How to Use tmux on a Linux VPS for tmux or How to Use GNU Screen on a Linux VPS for GNU Screen. For the Nginx configuration examples in this article, see the full guide at Nginx Administration on a VPS.
Copyright 2026 Virtua.Cloud. All rights reserved. This content is original work by the Virtua.Cloud team. Reproduction, republication, or redistribution without written permission is prohibited.
Ready to try it yourself?
Deploy your own server in seconds. Linux, Windows, or FreeBSD.
See VPS Plans