// ZSH-NGINX — NGINX COMPLETION + SERVICE-WRAPPER ALIASES

zsh plugin · nginx tab completion · aliases ngt / ngr for test + restart · vhost templates

GitHub Issues
// Color scheme

>_ZSH-NGINX

nginx vhost lifecycle, one tab away. A zsh plugin for the Debian/Ubuntu nginx layout ($NGINX_DIR/sites-available/ holds configs, $NGINX_DIR/sites-enabled/ is a symlink farm). Three autoloaded functions — en, dis, vhost — cover create / enable / disable; two aliases — ngt, ngr — cover the test / restart cycle; three filesystem-driven completions feed real on-disk site names into <TAB>.

Overview

zsh-nginx is a single source line that registers a small surface for managing nginx virtual hosts on the Debian-style split layout. Sourcing the plugin sets two environment defaults, probes for sudo, defines the ngt / ngr aliases, prepends src/ (completions) and appends autoload/ (functions) to fpath, and registers en / dis / vhost via autoload -Uz. Nothing else runs at source time — the function bodies load lazily on first call. Re-sourcing the plugin is idempotent: the env defaults use : ${VAR:=default} so existing values are never clobbered.

en NAMEEnable a site — symlink it from sites-available into sites-enabled
dis NAMEDisable a site — remove its sites-enabled symlink (config untouched)
vhost … NAMEGenerate a vhost config from a template, optionally enable it and write /etc/hosts
ngtTest the running nginx config (nginx -t)
ngrRestart the nginx service

Install

# Zinit
zinit ice lucid nocompile
zinit load MenkeTechnologies/zsh-nginx

# Oh My Zsh
git clone https://github.com/MenkeTechnologies/zsh-nginx \
    "$HOME/.oh-my-zsh/custom/plugins/zsh-nginx"
# then: plugins+=(zsh-nginx)

# Manual
git clone https://github.com/MenkeTechnologies/zsh-nginx
source zsh-nginx/zsh-nginx.plugin.zsh

Aliases

ngt$sudo nginx -t — test the running config for syntax errors
ngr$sudo service nginx restart — restart the service

Both aliases are prefixed with $sudo. The entrypoint probes which -p sudo at source time: if sudo is on PATH the prefix is sudo, otherwise it is the empty string and the command runs as the current user. On a systemd-only box where service nginx restart is not wired up, redefine the ngr alias to use systemctl restart nginx.

Functions

// en NAME

Enables a site by creating ln -s $NGINX_DIR/sites-available/NAME $NGINX_DIR/sites-enabled/NAME. It refuses to run without a name, errors if the config does not exist in sites-available, and reports if the site is already enabled. After the symlink is created it re-checks that the link materialised before printing success. Because it is a symlink (not a copy or move), disabling and re-enabling is lossless.

// dis NAME

Disables a site by rm -f $NGINX_DIR/sites-enabled/NAME — it removes only the symlink, never the underlying config in sites-available. It requires a name, errors if the site is not currently enabled, and re-checks that the symlink is gone before reporting success.

// vhost [options] NAME

Generates a vhost config from a template and (by default) enables it. The flow: parse flags with getopts, resolve the template, look up the owning user in /etc/passwd, compute a PHP-FPM pool port as "1" + the user's UID, sed-substitute {vhost} / {user} / {pool_port} into the template, move the result into sites-available/NAME, then optionally call en NAME and optionally splice a 127.0.0.1 NAME mapping into /etc/hosts.

-lList enabled vhosts (ls $NGINX_DIR/sites-enabled) and return — short-circuits before generation
-u USERSet the owning user (default $USER); used for the web root and fastcgi socket, looked up in /etc/passwd
-t TPLTemplate to use (default $NGINX_VHOST_TEMPLATE); searched under $ZSH/plugins/nginx/templates/$TPL first, then accepted as a raw path
-nGenerate only — skip the trailing en auto-enable
-wWrite a 127.0.0.1 NAME entry into /etc/hosts for local-only resolution
-hPrint the usage banner and return

Completion

Each function ships a paired #compdef completion. Candidates come from live filesystem state — ls -a over the relevant directory piped through an awk filter — not a hand-maintained list, so a site added by hand outside the plugin still tab-completes.

en <TAB>configs in $NGINX_DIR/sites-available (filter /^[a-z][a-z.-]+$/)
dis <TAB>configs in $NGINX_DIR/sites-enabled (filter /^[a-z][a-z.-]+$/)
vhost <TAB>project directories in $HOME/www (filter /^[^.][a-z0-9._]+$/)

Templates

Two stock vhost templates ship in templates/, both targeting per-user PHP-FPM over a unix-socket fastcgi backend and both denying .ht* dotfiles. Substitution is a single sed pass over three placeholders: {vhost}, {user}, {pool_port}. To add your own, drop a file into $ZSH/plugins/nginx/templates/ and select it with vhost -t NAME.

symfony2Web root /home/{user}/www/{vhost}/web, front controller app_dev.php, fastcgi scoped to app/app_dev/check.php, client_max_body_size 10M, per-vhost error+access logs
plain_phpWeb root /home/{user}/www/{vhost}, front controller index.php, fastcgi scoped to any .php, per-vhost error+access logs

Configuration

Two environment variables, both with : ${VAR:=default} defaults set at source time (existing values are preserved on re-source).

NGINX_DIRRoot for sites-available/ + sites-enabled/ — default /etc/nginx
NGINX_VHOST_TEMPLATEDefault template when vhost is called without -t — default $ZSH/plugins/nginx/templates/symfony2

Examples

nginx <TAB>            # nginx flags / signals (system completion)
ngt                    # test running config ($sudo nginx -t)
ngr                    # restart service ($sudo service nginx restart)

vhost foo              # generate sites-available/foo from the default
                       #   template and enable it
vhost foo -w           # ...and also add "127.0.0.1 foo" to /etc/hosts
vhost foo -t plain_php # use the plain_php template instead
vhost foo -n           # generate only, do not enable
vhost foo -u deploy    # own the vhost as user "deploy"
vhost -l               # list currently enabled vhosts
vhost -h               # usage banner

en  foo <TAB>          # complete from sites-available
dis foo <TAB>          # complete from sites-enabled

# full local-dev loop:
vhost foo -w && ngt && ngr

Troubleshooting

"The name of the vhost is required!"en / dis / vhost were called without a NAME argument
"NAME doesn't exist"en — no matching config in $NGINX_DIR/sites-available; create it (e.g. with vhost) first
"NAME is already enabled"en — the sites-enabled symlink already exists; nothing to do
"User USER doesn't have an account"vhost — the -u user is not in /etc/passwd
Permission denied on /etc/nginxsudo was not found on PATH at source time, so the prefix is empty; run as root or install sudo
ngr fails on a systemd boxredefine ngr to use systemctl restart nginx

Deeper internals — LOC breakdown, the vhost pipeline diagram, test coverage and design decisions — are in the Engineering Report.

Sibling plugins

Part of the MenkeTechnologies zsh plugin family — the MenkeTechnologiesMeta umbrella: