Nginx config files run deep with nesting and blocks; a single site routinely unfurls into dozens of lines of location. Without syntax highlighting, low-grade mistakes like an unclosed quote or a mismatched brace are hard to spot at a glance, and when nginx -t complains you have to hunt through the file line by line. This post gives editor-specific instructions for turning highlighting on: VS Code is a one-click install from the extension marketplace; Vim gets a 30-second recognition health check first — recent Vim versions have folded Nginx recognition into their bundled runtime, so it works out of the box, and only a failed check warrants copying the official syntax files from the Nginx source package (both paths fully tested).

Jump to the section for your editor:

  • On VS Code → Section 1, done in two minutes;
  • On Vim → Section 2, run the health check before deciding whether to install anything, with a control-group test and two real pitfalls attached.

VS Code: Install One Extension

VS Code’s built-in language support has no Nginx config, so an extension fills the gap. Open the extension marketplace (Ctrl+Shift+X), search nginx.conf, and install the one with high install counts. Two things to weigh when picking: first, update recency — Nginx directives grow year by year (such as grpc_pass and the http2 family), and a long-unupdated extension will flag those new directives as “unknown”; second, install count — an extension with millions of installs essentially never mislabels keywords.

No extra configuration is needed after installing: open any .conf file or a file under an nginx config path, and seeing the language mode in the bottom-right status bar read nginx means it’s active. If a .conf file isn’t auto-recognized, click the language mode in the status bar and pick nginx manually once; VS Code remembers the association.

For projects where config file names vary and you want a set-and-forget solution, use the workspace’s files.associations to batch-associate file name patterns with the nginx language:

1
2
3
4
5
6
{
"files.associations": {
"*.conf": "nginx",
"**/nginx/**": "nginx"
}
}

Put it in .vscode/settings.json and commit it with the repo when the team shares one, so every collaborator opens the project in a highlight-ready state and nobody has to hand-pick the language mode.

Vim: Run the 30-Second Recognition Health Check First

Don’t rush to install anything. Recent Vim versions ship with Nginx syntax, indent, and filetype recognition built in — tested on vim 9.1 from Alpine 3.20 (no syntax files copied): nginx.conf, app.nginx, and configs under /etc/nginx/ all open as filetype=nginx, with syntax, indent, and filetype plugin all three present under /usr/share/vim/vim91/.

The health check takes one step — open any nginx config in Vim and ask for the file type:

1
2
vim /etc/nginx/nginx.conf
# the bottom command :set ft? should output filetype=nginx

An output of filetype=nginx means the built-in recognition is working and you can skip the next two subsections entirely; an empty output or conf is the only case that requires reading on. To see the fuller picture, run a small comparison experiment: save the same server block under three file names and ask :set ft? of each — results below, measured for real.

Side-by-side test of vim 9.1 built-in recognition

File name :set ft? result Notes
nginx.conf nginx The main config name matches by default
app.nginx nginx The *.nginx suffix is the universal fallback
app.conf conf Arbitrary names go unrecognized — by design of the rules
/etc/nginx/real.conf nginx System config paths match first

The most practical row in the table is the second: to get highlighting for loose config fragments you’ve split out yourself, just rename them with an .nginx suffix; dropping them into /etc/nginx/ works equally well. app.conf being recognized as conf is not a bug — the recognition rules match on file name and path, not by reading the content and guessing the language.

Vim: When Built-In Recognition Is Missing, Copy the Syntax Files from the Nginx Source Package

A failed health check usually means an older Vim. The orthodox remedy in that case has always been the contrib/vim/ directory of the Nginx source package — officially maintained by Nginx, updated with every release, with syntax rules that track nginx’s new directives, more reliable than third-party scripts.

First get the source package:

1
2
3
curl -LO https://nginx.org/download/nginx-1.28.0.tar.gz
tar xzf nginx-1.28.0.tar.gz
cd nginx-1.28.0

contrib/vim/ contains four directories, each handling one job:

Directory Purpose
syntax Highlighting rules (coloring of directives, strings, comments)
indent Automatic indentation by server/location block
ftdetect Decides which files are treated as nginx syntax
ftplugin nginx-file-specific editing behavior (comment string, etc.)

Then copy them wholesale into Vim’s runtime directory:

1
2
mkdir -p /usr/share/vim/vimfiles/
cp -r contrib/vim/* /usr/share/vim/vimfiles/

Run mkdir before copying — don’t skip it. In an Alpine container, running cp -r directly fails with cp: can't create directory '/usr/share/vim/vimfiles/ftdetect': No such file or directory — the vimfiles directory isn’t pre-created on quite a few stripped-down systems, and its declaration in rpath doesn’t make it exist. The vim packages on distros like Debian and CentOS usually pre-create it, but adding mkdir -p is never wrong on any system. The full run record from tripping over the pitfall to a finished install:

Live test of the contrib/vim copy and the mkdir pitfall

After installing, rerun the health check above; :set ft? must turn into filetype=nginx before you can call it done. The ftdetect rules in contrib/vim are narrower than the newer Vim’s built-ins — in the 1.28.0 source package there are only four: the *.nginx suffix, a file name exactly nginx.conf, and the /etc/nginx/ and /usr/local/nginx/conf/ paths; the built-in rules additionally cover variants like nginx*.conf and */nginx/*.conf. If app.conf still goes unrecognized after copying, either rename it to .nginx or move it into /etc/nginx/.

A Pitfall in Headless Scenarios

Recognition triggers depend on Vim’s filetype machinery. In interactive use, mainstream distros turn it on — although Alpine’s default vimrc has no explicit filetype on line, interactive-mode tests still recognized all three files in the table above. The real trap is headless: the silent ex mode vim -es commonly used in scripts loads no vimrc at all, the filetype machinery never starts, and :set ft? outputs nothing; adding filetype detect explicitly to the command chain restores it (the health check itself was run as vim -es -c "filetype detect" -c "set ft?" -c q <filename>). If you batch-check file types in scripts, remembering this switch saves most of the troubleshooting time.

Two changes are noticeable the moment installation completes. First, structure becomes readable: block directives like server, location, and upstream pick up color, nesting levels stand out at a glance, and a dropped opening brace shows itself instantly as the rest of the file “goes color-wild.” Second, indentation automates: the indent script aligns new location blocks to their parent, saving every minute spent hand-typing spaces. As always, nginx -t after editing; highlighting’s job is to stop the low-grade errors at step one.

If it’s installed but still black-and-white, check three things in order: first, whether the file name trips a recognition rule (most common — renaming to .nginx verifies instantly); second, whether the filetype machinery was switched off by your own vimrc; third, that the copy destination is the same directory as one of the paths in set rtp? output — if the paths don’t line up, copying the files is the same as not copying them.

Caveats

  • Extensions and syntax files affect only the editor’s display; they have no say over whether the config is correct. After saving changes and before reload, nginx -t remains the non-negotiable verification step.
  • contrib/vim/ comes from the Nginx source package; before copying, confirm the current directory is the unpacked source root. Syntax files don’t auto-update when Nginx upgrades — re-copy them after significant version changes. On setups where the newer Vim already has built-in recognition, this whole step can be skipped.
  • Vim’s runtime directory varies by system and compile options; vim -es -c 'set rtp?' -c q lists the actual search paths on your machine, and the copy destination can be any writable one from the output.
  • When editing configs on a server with no way to install syntax files, nginx -t errors locate the problem themselves — in testing, putting a server block outside http (single-line file /tmp/bad2.conf) produced nginx: [emerg] "server" directive is not allowed here in /tmp/bad2.conf:1, with file name and line number right at the end. Read the line number and jump there; don’t count braces with the naked eye.

This article was rebuilt from the author’s CSDN blog posts written between 2020 and 2024, originally published on CSDN.