Bootstrap script for Azure Linux VMs that leverages the local temporary disk (/mnt
) to boost performance of Nginx, PHP (all versions), ASP.NET Core, and WordPress.
It auto-creates and permissions high‑IO temp/cache paths under /mnt
.
This script does not modify PHP configuration files — you keep full control. It works with all PHP versions (5.x/7.x/8.x/…).
Azure offers an ephemeral local disk (often mounted at /mnt
) backed by SSD/NVMe with very low latency and high IOPS.
Because its contents are not persistent (lost on deallocation/host change), it’s perfect for temporary data:
- Nginx proxy/FastCGI cache and temp files
- PHP session files and temporary upload directory
- ASP.NET Core temp files (
TMPDIR
) - WordPress export/cache artifacts
Benefits:
- Lower latency & higher throughput for temp/cached data
- Less pressure on your OS/data managed disks
- Cost‑effective performance boost (no extra managed disks just for cache/temp)
⚠️ Do not store databases or critical logs on/mnt
.
Creates (and fixes perms/ownership) the following directories:
/mnt/nginx/fastcgi/
– Nginx FastCGI cache/mnt/nginx/proxy/
– Nginx reverse‑proxy cache/mnt/nginx/temp/
– Nginx temp (proxy/fastcgi)/mnt/php/sessions/
– PHP session files/mnt/php/uploads/
– PHP temporary upload dir/mnt/dotnet/temp/
– .NET temporary path (TMPDIR
)/mnt/wordpress/
– WordPress temp/cache/export (optional)
It also ensures /run/php
exists (common pitfall for FPM sockets).
The script does not edit PHP
.ini
files or reload services — you configure PHP once and the script just guarantees the required directories exist at every boot.
- Ubuntu/Debian VM on Azure with
/mnt
mounted - systemd
- Nginx (optional but recommended)
- PHP (any version) if you run PHP/WordPress
- Root/sudo privileges
# 1) Install the bootstrap script
sudo install -d /usr/local/sbin
sudo install -m 0755 scripts/azure-tempdisk-bootstrap.sh /usr/local/sbin/azure-tempdisk-bootstrap.sh
# 2) (Optional) Overrides
sudo install -D -m 0644 config/azure-tempdisk-bootstrap /etc/default/azure-tempdisk-bootstrap
# 3) Systemd unit
sudo install -D -m 0644 systemd/azure-tempdisk-bootstrap.service /etc/systemd/system/azure-tempdisk-bootstrap.service
# 4) Enable & start
sudo systemctl daemon-reload
sudo systemctl enable azure-tempdisk-bootstrap.service
sudo systemctl start azure-tempdisk-bootstrap.service
sudo systemctl status azure-tempdisk-bootstrap.service --no-pager
# Directories should exist with proper perms
ls -ld /mnt/nginx/* /mnt/php/* /mnt/dotnet/temp /mnt/wordpress 2>/dev/null || true
To take advantage of the Azure temporary disk with Nginx you can choose between two approaches:
If your server hosts many sites with different caching needs, configure cache and temp paths per virtual host, by editing the specific configuration files. This offers fine‑grained control (different cache zones, sizes, TTLs, or paths per site).
Example directives to add:
# Inside http { ... } or server { ... }
proxy_temp_path /mnt/nginx/temp 1 2;
fastcgi_temp_path /mnt/nginx/temp 1 2;
proxy_cache_path /mnt/nginx/proxy levels=1:2 keys_zone=PROXYCACHE:256m
max_size=20g inactive=12h use_temp_path=off;
fastcgi_cache_path /mnt/nginx/fastcgi levels=1:2 keys_zone=WORDPRESS:128m
max_size=10g inactive=60m use_temp_path=off;
Then enable caching (proxy_cache
or fastcgi_cache
) inside the appropriate server { ... }
blocks for each site.
If your server runs a few sites or they can share a common caching strategy, use the provided configuration file conf/nginx/azure-tempdisk-cache.conf
to set global temp paths and cache zones on /mnt
.
Install it like this:
sudo install -D -m 0644 conf/nginx/azure-tempdisk-cache.conf /etc/nginx/conf.d/azure-tempdisk-cache.conf
sudo nginx -t && sudo systemctl reload nginx
This sets up:
- temp directories (
proxy_temp_path
,fastcgi_temp_path
) on/mnt
- global caches (
PROXYCACHE
andWORDPRESS
) ready to use - predefined cookie‑based rules to bypass cache for logged‑in users or WooCommerce carts
Then include the provided snippets (wordpress-server-snippet.conf
, dotnet-server-snippet.conf
) inside your server { ... }
blocks as needed.
Rule of thumb: use Manual for multi‑tenant, heterogeneous environments; use Semi‑automatic for simpler stacks with uniform rules.
Since all cache and temp paths point to /mnt
, it’s critical that Nginx only starts after the bootstrap service has finished. Otherwise, Nginx may fail to start or create temp directories on the root disk by mistake.
To enforce this, create a systemd drop-in override for Nginx:
sudo systemctl edit nginx
Paste the following:
[Unit]
# Ensure Nginx waits for the bootstrap and the /mnt mount
Requires=azure-tempdisk-bootstrap.service
After=azure-tempdisk-bootstrap.service
RequiresMountsFor=/mnt
(if After
is already present, append the new value to the existing ones)
Then reload and restart:
sudo systemctl daemon-reload
sudo systemctl enable nginx
sudo systemctl restart nginx
With this configuration:
Requires
+After
make Nginx wait until the bootstrap service has completed.RequiresMountsFor=/mnt
ensures that/mnt
is mounted before Nginx starts.
This guarantees that Nginx always finds the correct temp/cache directories on the Azure ephemeral disk at startup.
Configure once in your PHP configuration (this applies to PHP‑FPM and any other SAPIs):
- In your
php.ini
(or a dedicated.ini
for the FPM SAPI, or a per‑pool override such as/etc/php/<ver>/fpm/pool.d/*.conf
), set:session.save_path = "/mnt/php/sessions" upload_tmp_dir = "/mnt/php/uploads"
- If you’re using PHP‑FPM, reload the specific FPM service so changes take effect:
sudo systemctl reload php8.2-fpm # or php8.3-fpm / php7.4-fpm / your version
- For other PHP modes (CLI, Apache mod_php, etc.), a service reload may not be needed, but the same
php.ini
directives apply.
The bootstrap script only creates and maintains the directories; it does not edit PHP config nor reload services.
Set the temp path in your Kestrel unit:
[Service]
Environment=TMPDIR=/mnt/dotnet/temp
Then:
sudo systemctl daemon-reexec
sudo systemctl restart kestrel-yourapp.service
Override defaults in /etc/default/azure-tempdisk-bootstrap
:
# DOTNET_TMP_DIR=/mnt/dotnet/temp
# NGX_FASTCGI_DIR=/mnt/nginx/fastcgi
# NGX_PROXY_DIR=/mnt/nginx/proxy
# NGX_TEMP_DIR=/mnt/nginx/temp
# PHP_SESS_DIR=/mnt/php/sessions
# PHP_UPLOAD_DIR=/mnt/php/uploads
# WP_DIR=/mnt/wordpress
One of the most common questions is: why did we choose to provide a dedicated systemd
service instead of just adding the bootstrap script to rc.local
, cron @reboot
, or similar mechanisms?
The answer comes down to reliability and timing:
-
Mount timing
On Azure, the ephemeral disk (/mnt
) is mounted by the Azure Linux Agent (waagent
) or cloud-init after the basic system initialization.
If the bootstrap script runs too early,/mnt
may still be empty (or just a plain directory), and the whole setup would silently fail. -
Explicit dependency management
Withsystemd
we can declareRequiresMountsFor=/mnt
andAfter=local-fs.target
, ensuring that the service only runs once the ephemeral disk is properly mounted and available. -
Idempotence & safety
The service runs inoneshot
mode and exits after creating directories and permissions.systemd
guarantees that it is executed exactly once per boot and in the correct order. -
Integration with other services
By declaringBefore=nginx.service
(or other services), we ensure that Nginx, PHP-FPM, or .NET apps never start without their required temp/cache directories being present. -
Maintainability
Usingsystemd
keeps everything in the same place as other system services, making it easy to check logs withjournalctl
, enable/disable the bootstrap, or update the script.
In short: a plain script at boot time is fragile because it might run before /mnt
is ready. A dedicated systemd
unit makes the setup predictable, reliable, and fully integrated into the Linux service lifecycle.
/mnt
missing: ensure your VM size/image mounts the Azure temp disk at/mnt
.- Permissions:
www-data
(or your web user) should own/mnt/nginx
,/mnt/php
,/mnt/dotnet/temp
,/mnt/wordpress
. - PHP not using
/mnt
: verify your PHP config and reload the FPM service if applicable. - Nginx cache not hit: check
X-Proxy-Cache
/X-FastCGI-Cache
headers and keys_zone names.
MIT (see LICENSE
).
- Official GitHub repo: https://github.com/Ryadel/azure-tempdisk-bootstrap
- Documentation & examples: https://www.ryadel.com/en/boost-azure-web-server-performance-azure-tempdisk-bootstrap/