Ready‑to‑Use Web Runtime
Compiles Nginx 1.28.0 (dav‑ext / http2 / stream modules), optional PHP 8.2–8.5 and MariaDB 10.6 / 10.11, with sensible defaults.
Install Nginx, PHP, and MariaDB (bundled with the Mroonga search engine) with a single command. Kernel/network tuning, WebDAV, and certificate configuration are automated. A ready‑to‑run production base for small/medium sites, edge nodes, and on‑prem projects.
apt install -y curl curl -fL https://wnmp.org/wnmp.sh -o wnmp.sh chmod +x wnmp.sh bash wnmp.sh
Script open-source license: GPLv3. Please execute commands using the root account on a completely clean system.
v1.10 Modify SSH key logic: When multiple SSH keys are requested, only the latest public-private key pair remains valid. Older public keys are backed up and preserved.
v1.09 Delete the default site's .pem file to avoid confusion. The default site will only generate a .pem certificate file after formally applying for a certificate.
v1.05 Perform an overlay installation or execute `bash wnmp.sh remariadb`. First, create a full database backup at: /home/all_databases_backup_[time].sql.gz
v1.04 Pure Cloud Storage Site Blocking.php File, Preventing Source Code Download
v1.03 Optimize Nginx parameters to accelerate SSL certificate validation
v1.02 Added --pcntl extension, compatible with workerman
WNMP:
1、Windows11(WSL)+Nginx+Mariadb+PHP
(Deployed in a Linux subsystem running on Windows 11 - WSL, **not** an .exe environment package)
2、(Linux)WebDav+Nginx+Mariadb+PHP
Compiles Nginx 1.28.0 (dav‑ext / http2 / stream modules), optional PHP 8.2–8.5 and MariaDB 10.6 / 10.11, with sensible defaults.
Enables BBR/FQ, reasonable somaxconn and file descriptors, disables THP; writes sysctl and limits automatically with safe downgrades for WSL.
Integrated acme.sh. Prefers Cloudflare DNS‑01; automatically falls back to webroot; installs certs and reloads Nginx.
One‑click vhost creation, built‑in phpMyAdmin protection, WebDAV account management; supports separate password files per domain.
Unified, straightforward directories:
/usr/local/nginx /usr/local/php /home/wwwroot
Blocks hidden paths and dangerous extensions; sensible timeouts and cache; turns off unnecessary PHP options by default.
bash wnmp.sh
bash wnmp.sh status
bash wnmp.sh sshkey
bash wnmp.sh webdav
bash wnmp.sh default
bash wnmp.sh vhost
bash wnmp.sh tool
bash wnmp.sh restart
bash wnmp.sh remove # clean everything bash wnmp.sh renginx # clean Nginx only bash wnmp.sh rephp # clean PHP only bash wnmp.sh remariadb # clean MariaDB only
bash wnmp.sh wslinit
Place the following HTML into your website footer:
<small>This server is built by the <a href="https://wnmp.org" target="_blank" rel="noopener">wnmp.org</a> one‑click installer</small>
The script is released under GPLv3. Commercial use and redistribution are allowed, but derivative works must remain open under the same license. Please follow the licenses of third‑party dependencies.
Primarily aimed at Debian 12/13 and Debian‑like systems. Verified on Windows11(WSL), (Linux)Debian 13, Debian 12, Ubuntu 22.04, Ubuntu 24.04, and Ubuntu 25.10. WSL (Debian recommended) receives safe downgrades.
For production, Debian13 is recommended. WNMP does not plan to support non‑Debian‑like distributions or EOL Debian variants.
Confirm you are using the Windows 11 operating system. First, you need to install the WSL subsystem.
Press Win+R to open the Run dialog box, then type cmd. Press Shift+Ctrl+Enter to enter the Administrator mode console.
wsl -l -o # Check if the remote system list can be read. If it reads normally, WSL is functioning correctly.
wsl --install debian # (Begin installing the Debian 13 subsystem. The first time you run this command, you may be prompted to restart your computer or notified that CPU virtualization support is disabled. Follow the on-screen instructions accordingly.)
After a normal installation, you will be prompted to configure a standard account and password. Once configured successfully, simply type: exit to exit the subsystem.
wsl -d debian -u root # Log in to the Debian system as the root user.
cd ~ apt update && apt install -y curl && curl -fL https://wnmp.org/wnmp.sh -o wnmp.sh && chmod +x wnmp.sh && bash wnmp.sh wslinit
In the address bar of this computer task, navigate to and open C:\Users\[username]\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup # Replace [username] with your actual Windows login username.
Create a new wsl.vbs file and write the following content:
Set ws = CreateObject("Wscript.Shell") ws.run "wsl -d debian", 0
After initialization completes, the subsystem has installed the SSH server. Restart your computer as prompted, and you can then log in to your WSL Debian subsystem using an SSH client just like a regular server VPS.
Login address: 127.0.0.1 Port: 22
Additional WSL commands: In the Windows CMD environment, non-subsystem shell console
wsl -l -v # View list of installed systems
wsl --shutdown # Stop Subsystem
wsl --unregister debian # Uninstall Subsystem
If you need to access the subsystem via a local area network, open C:\Users\[username] # Please replace with your actual Windows login username.[username]
Create a new .wslconfig file and write the following content:
[wsl2] networkingMode=Mirrored dnsTunneling=true firewall=true autoProxy=true [experimental] hostAddressLoopback=true
Run the following command in an administrator PowerShell window to configure Hyper-V firewall settings to allow inbound connections:
Set-NetFirewallHyperVVMSetting -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -DefaultInboundAction Allow
Restart your computer again. You can now log into the subsystem using the same LAN IP address as your local Windows system. Enter `ipconfig` in the Command Prompt to view your local LAN IP address.
Because the most secure server is the one without a control panel.
GUI-based panel software (such as BT Panel) makes server management easier, but it also brings:
🔓 Extra open ports (e.g., 8888) that expand the attack surface;
⚠️ Retaining SSH password login, which increases brute-force attack risks;
🧩 Long-running panel daemons that may be exploited or escalated;
🔄 Auto-update and plugin systems that reduce auditability.
WNMP follows a completely different philosophy:
✅ SSH key-only login by default (the most secure authentication method);
✅ No web panel ports — after deployment, almost zero persistent processes;
✅ Fully transparent configuration — scriptable, versionable, and auditable;
✅ Focus on host-level performance and security baseline, not GUI convenience.
WNMP’s goal is not to “replace BT Panel,” but to provide a clean, engineer-oriented environment template — the command line itself is the control panel, where security and control always come first.
Panels are for beginners; WNMP is for engineers.
WNMP does not simply “package Nginx + PHP + MariaDB into a container.” Instead, it enables one-click host-level performance tuning and security baseline configuration (kernel network parameters, ulimit restrictions, SSH key setup, compilation optimizations, etc.) within a clean system environment.
These host-level capabilities are often uncontrollable within containers or require high privileges like --privileged, which undermines the original intent of container isolation.
Therefore, WNMP is recommended for use within KVM virtual machines, cloud servers, or KVM virtual systems running on Proxmox (PVE) to fully leverage its performance tuning and system optimization advantages.
Without MariaDB: minimum 512 MB RAM on Debian (the OS itself uses ~200 MB). On Ubuntu, minimum 768 MB RAM (the OS uses ~500 MB).
With MariaDB installed: at least 1 GB RAM is required for a proper installation.
Only PHP 8.2 – 8.5 are supported.
WNMP intentionally does not support EOL legacy versions.
pecl install xxx
After installation, edit /usr/local/php/php.ini and add extension=xxx.so.
Verify with php -m.
Run bash wnmp.sh restart or systemctl restart php-fpm to reload PHP‑FPM and enable the extension.
WNMP uses official download sources only. No third‑party mirrors are used.
If your download speed is extremely slow, try switching to a different system update source or install via proxy. For security reasons, always use the official download source!
Upstream releases appear first on official websites/GitHub, while Debian/Ubuntu repos may lag. Compiling also allows optional modules.
For example, WebDAV requires nginx-dav-ext-module.
As another example, Swoole supports PHP 8.5 on GitHub already, while some package repos lag; with WNMP you can use Swoole on PHP 8.5 immediately.
WNMP builds PHP with swoole, apcu, inotify, and redis enabled by default.
Since the WNMP author is also the LOWPHP author, WNMP ensures LOWPHP runs well. Traditional PHP‑FPM projects also run normally on WNMP.
apcu is an official optional extension. It offers excellent single‑process performance but is unsuitable for PHP‑FPM’s short‑lived workers; your code still runs normally though.
inotify is also an official optional extension for real‑time file change monitoring.
LOWPHP is a persistent‑memory runtime that leverages native C extensions for caching and hot‑reload. It’s similar in spirit to FrankenPHP (Go‑style) but built natively for PHP. It is both a runtime and a framework, enabling high‑performance apps with a familiar PHP‑FPM‑like development model and multi‑site support. Coming soon.
For DNS‑01 via Cloudflare: after compiling/installing Nginx with wnmp.sh, go to Cloudflare → My Profile → API Tokens → Create Token, choose “Edit zone DNS” to generate a token, then on the server run:
echo "SAVED_CF_Token='YOUR_TOKEN_HERE'" >> ~/.acme.sh/account.conf
If valid Cloudflare creds and dns_cf.sh are detected, DNS‑01 is preferred; otherwise it falls back to webroot. After issuance WNMP writes cert paths and reloads Nginx.
We recommend DNS‑01. With webroot, if a CDN is enabled, renewals may fail because the origin may not be reachable directly.
Yes. The script detects internal network environments and prompts whether to force certificate application. Selecting "No" skips certificate application, ideal for development environment installation and debugging. Selecting "Yes" enables certificate application similar to installing within a PVE NAT IPv4 virtual LAN. As long as the PVE host forwards ports 80 and 443 to the current internal KVM virtual machine, certificates can be applied normally.
FTP is plaintext by default, making credentials easy to intercept. Even with TLS it’s cumbersome. Disable FTP server software entirely.
WebDAV rides on HTTPS (443) with SSL protection.
On Windows, use WinSCP (as with FTP) or RaiDrive (map as a local drive). On Linux, use Rclone to mount.
WebDAV supports multiple accounts per site. Run bash wnmp.sh webdav repeatedly for the same domain to add more accounts. Password files are stored under /home/passwd/.
WinSCP settings: Protocol: WebDAV; Host: [domain]/webdav; Encryption: TLS/SSL implicit; Port: 443.
Other clients: https://[domain]/webdav.
Replace [domain] with your real domain.
Yes. When creating a site with bash wnmp.sh vhost or adding WebDAV via bash wnmp.sh webdav, choose “public directory: yes”. WNMP will disable all .php execution and serve any extension as a downloadable file.
If used purely as a drive, you can install Nginx only (skip PHP and MariaDB).
MariaDB is an open‑source fork by the original MySQL authors. It is highly compatible with MySQL syntax—migrate/import and it should just work.
To support low‑spec VPS (e.g., 1 GB RAM) and because the divergence between MariaDB and MySQL grows in newer releases (e.g., default collations/encodings differ).
WNMP ships MariaDB with Mroonga. The Mroonga project officially supports up to MariaDB 10.x.
Databases need not always be the newest. For compatibility and resource constraints, WNMP supports actively maintained MariaDB 10.x branches. If you need other versions, modify WNMP as needed.
MariaDB includes an optional Mroonga engine in multiple versions, but those are often outdated. WNMP disables the built‑in variant and installs the latest Mroonga separately.
MariaDB’s Mroonga page: https://mariadb.com/docs/server/server-usage/storage-engines/mroonga/about-mroonga
Mroonga official site: https://mroonga.org/
For MySQL/MariaDB projects, performance bottlenecks often come from query speed. Avoid LIKE fuzzy search—it’s slow!
Switch your table engine to Mroonga and add full‑text indexes on varchar/text columns. Example:
SELECT name FROM users WHERE MATCH (name) AGAINST ('+Hello Word' IN BOOLEAN MODE); (Replace field/table names with your own.)
See the Mroonga site for more documentation. https://mroonga.org/
Many Nginx installs don’t consider a default site certificate. If only port 80 is served, a request to https://[ip]/ may be routed to the first 443 vhost, risking MITM.
Therefore, the WNMP default site listens on both ports 80 and 443. To prevent database access via the incorrect methods http://[ip]/phpmyadmin or https://[ip]/phpmyadmin, which pose a man-in-the-middle attack risk, Accessing the default site requires executing `bash wnmp.sh default`. Only after configuring a subdomain for the default site and successfully obtaining a certificate can the database be accessed via `https://[domain]/phpmyadmin`.
After running bash wnmp.sh default (bind a subdomain + certificate), visit https://[domain]/phpmyadmin. Nginx Basic Auth is enabled by default. Username: wnmp. Password: [needpasswd] or your MariaDB root password (depending on setup).
To change BasicAuth for the default site: htpasswd -bc /home/passwd/.default [user] [password]. (The default site supports a single account.)
Once BasicAuth succeeds, log in to phpMyAdmin as root with your MariaDB root password.
MariaDB listens on localhost (not 127.0.0.1); use localhost in your app configs.
Alternatively, manage via the shell by running mysql.
For Mroonga tables, do not import/export via phpMyAdmin (it does not consider Mroonga specifics).
Prefer mysqldump for import/export on the server:
All databases (with accounts/privileges/routines/events): mysqldump --all-databases --single-transaction --default-character-set=utf8mb4 --routines --events --flush-privileges | gzip > all_databases_backup.sql.gz
Single DB: mysqldump --single-transaction --default-character-set=utf8mb4 --databases test | gzip > test.sql.gz
Import: gunzip < all_databases_backup.sql.gz | mysql --default-character-set=utf8mb4
Import: gunzip < test.sql.gz | mysql --default-character-set=utf8mb4
Yes. Version v1.05 now supports overwriting installations. Alternatively, run `bash wnmp.sh remariadb` to perform a full database backup to: /home/all_databases_backup_[time].sql.gz
Yes. Version 1.02 has just added the --pcntl extension, making it compatible with Workerman.
Yes. Install or remove components individually, or run only the kernel/network tuning.
Yes. Run bash wnmp.sh sshkey
===
⚠️ Important reminder: Before confirming you have saved the private key to your own computer
⚠️ Do not disconnect the current SSH session, or you will be unable to log back into the server!
===
Save the private key to your local computer. You can then load the key in an SSH client for password-less login.
After configuring key-based login, the server will block all username/password logins.
WNMP auto‑tunes parameters based on your hardware and OS for strong production performance.
Benchmark with ab, wrk, etc.
On identical hardware, compare with other scripts. Results may vary and are for reference only.
Note: When testing concurrency, disable CDN caching, use HTTP, and run e.g. ab -n100000 -c1000 -k http://... — the -k flag (Keep‑Alive) better simulates real browsers and yields higher performance.
No. The author commits to open‑source principles; wnmp.org is the only official website.
QQ Group: 1075305476
Telegram Group: https://t.me/wnmps
Github: https://github.com/lowphpcom/wnmp
The community source code is being built on LOWPHP — stay tuned!