MIME Types, Apache, Nginx and .htaccess: A Beginner-Friendly Guide to How Web Servers Deliver Files

Have you ever clicked a file on a website expecting it to download, only to see a browser page filled with strange characters such as:

����P�F��x��...

Or perhaps a PDF downloaded instead of opening in the browser, a CSS file was interpreted incorrectly, or a file with an unusual extension appeared as plain text.

In many cases, the file itself is perfectly fine.

The real problem is that the web server told the browser the wrong thing about the file.

This is where concepts such as MIME types, HTTP headers, Apache, Nginx, and .htaccess become important.

This guide explains these concepts from the ground up, without assuming previous server administration experience.


1. What Happens When You Download a File From a Website?

When you enter an address such as:

https://example.com/files/manual.pdf

your browser sends a request to the web server.

The server then sends a response containing two main things:

  1. HTTP headers
  2. The actual file data

A simplified response might look like this:

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Length: 245812

After the headers comes the actual PDF file.

The important line here is:

Content-Type: application/pdf

This tells the browser:

“The data I am sending you is a PDF document.”

The browser can then decide whether to display it, download it, or pass it to another application.


2. What Is a MIME Type?

A MIME type is a standardized way of describing what kind of content a file contains.

MIME originally stood for:

Multipurpose Internet Mail Extensions

Although MIME started with email, the same system became extremely important on the web.

A MIME type normally consists of two parts:

type/subtype

For example:

text/html
image/jpeg
application/pdf

The first part describes the general category.

The second part describes the specific format.


3. Common MIME Types

Here are some MIME types you will encounter frequently.

FileMIME type
HTMLtext/html
CSStext/css
JavaScripttext/javascript
Plain texttext/plain
JPEGimage/jpeg
PNGimage/png
GIFimage/gif
SVGimage/svg+xml
PDFapplication/pdf
ZIPapplication/zip
JSONapplication/json
XMLapplication/xml
MP4video/mp4
MP3audio/mpeg

There is also a very useful generic type:

application/octet-stream

This essentially means:

“This is arbitrary binary data.”

Browsers commonly treat application/octet-stream as something that should be downloaded instead of displayed.


4. File Extension vs MIME Type

A common misconception is that browsers determine a file’s type entirely from its extension.

For example:

document.pdf
archive.zip
photo.jpg

The extension is important, but when files are delivered over HTTP, the server normally sends a Content-Type header.

For example:

Content-Type: application/zip

The browser uses this information when deciding what to do with the response.

This means a server could theoretically send:

picture.jpg

with:

Content-Type: text/plain

The browser might then try to handle the JPEG as text.

That can result in a screen filled with strange characters.


5. Why Binary Files Look Like Garbage When Displayed as Text

Files such as:

  • ZIP archives
  • executables
  • images
  • videos
  • compressed backups

contain binary data.

Binary files are not meant to be displayed as normal characters.

If a browser receives a binary file but decides to display it as text, you may see something like:

�PNG
IHDR����
��x��...

or:

PK���...

The important thing to understand is:

This does not necessarily mean that the file is damaged.

The browser may simply be interpreting binary bytes as text characters.


6. The HTTP Content-Type Header

The HTTP header responsible for describing the file format is:

Content-Type

Examples:

Content-Type: text/html
Content-Type: application/pdf
Content-Type: application/zip
Content-Type: image/jpeg

For unknown binary files, a server administrator may use:

Content-Type: application/octet-stream

This is often appropriate for files that should simply be downloaded.


7. Content-Disposition: Open or Download?

There is another very important HTTP header:

Content-Disposition

This header can tell the browser whether the content should normally be displayed or downloaded.

For example:

Content-Disposition: inline

means:

Display the file inside the browser if possible.

While:

Content-Disposition: attachment

means:

Treat the response as a downloadable file.

A server can also suggest a filename:

Content-Disposition: attachment; filename="archive.zip"

The browser will normally show a download dialog using that filename.


8. Content-Type and Content-Disposition Work Together

These two headers solve slightly different problems.

Content-Type tells the browser:

What is this file?

Content-Disposition tells the browser:

What should I normally do with it?

For example:

Content-Type: application/pdf
Content-Disposition: inline

usually causes the PDF to open in the browser.

But:

Content-Type: application/pdf
Content-Disposition: attachment

normally causes the PDF to download.

For an unusual binary file:

Content-Type: application/octet-stream
Content-Disposition: attachment

is a common and safe combination.


9. Why Unusual File Extensions Can Cause Problems

Web servers usually maintain a list mapping file extensions to MIME types.

For example:

.html → text/html
.jpg  → image/jpeg
.pdf  → application/pdf
.zip  → application/zip

But imagine you have files such as:

backup.zip.001
backup.zip.002
backup.zip.003

These may be parts of a split archive.

The web server may look only at the final extension:

.001
.002
.003

These extensions may not exist in the server’s MIME type database.

The server may therefore:

  • use a default MIME type;
  • return text/plain;
  • return application/octet-stream;
  • omit an expected type;
  • allow another server component to guess.

The result depends on the hosting configuration.


10. What Is Apache?

Apache HTTP Server is one of the most widely used web servers.

Its job is to receive HTTP requests and return web pages, images, scripts, downloads, API responses, and other content.

A typical WordPress website may run something like:

Browser
   ↓
Apache
   ↓
PHP
   ↓
WordPress
   ↓
MySQL/MariaDB

Apache can be configured globally by the server administrator.

It can also, depending on the hosting setup, allow directory-level configuration through a special file called:

.htaccess

11. What Is .htaccess?

.htaccess is a configuration file used by Apache and compatible servers.

The name literally begins with a dot:

.htaccess

It normally contains Apache directives that apply to a directory and its subdirectories.

For example, .htaccess can be used for:

  • redirects;
  • URL rewriting;
  • WordPress permalinks;
  • access restrictions;
  • MIME types;
  • security headers;
  • caching rules;
  • compression;
  • forcing downloads.

12. A Simple .htaccess Example

Suppose you want files ending in .bin to be treated as binary downloads.

You might use:

AddType application/octet-stream .bin

Or for more control:

<FilesMatch "\.bin$">
    ForceType application/octet-stream
</FilesMatch>

This tells Apache that matching files should be returned as:

Content-Type: application/octet-stream

13. Forcing a File to Download With Apache

If Apache’s mod_headers module is available, you can also add:

<FilesMatch "\.bin$">
    ForceType application/octet-stream
    Header set Content-Disposition "attachment"
</FilesMatch>

The server will then return something similar to:

Content-Type: application/octet-stream
Content-Disposition: attachment

That strongly encourages the browser to download the file.


14. Matching Split Archive Files

Suppose your site contains:

archive.zip.001
archive.zip.002
archive.zip.003

A regular expression can match all three-digit archive parts:

<FilesMatch "\.zip\.[0-9]{3}$">
    ForceType application/octet-stream
    Header set Content-Disposition "attachment"
</FilesMatch>

This matches:

archive.zip.001
archive.zip.021
archive.zip.999

but not:

archive.zip
archive.zip.old
archive.zip.01

15. AddType vs ForceType

Apache offers several ways to control MIME types.

AddType

Example:

AddType application/octet-stream .001 .002 .003

This associates particular extensions with a MIME type.

It works well when you know the extensions in advance.

However, hundreds of numbered extensions would obviously be inconvenient.


ForceType

Example:

<FilesMatch "\.zip\.[0-9]{3}$">
    ForceType application/octet-stream
</FilesMatch>

This is more flexible because you can use a regular expression to select files.

For numbered archive parts, FilesMatch plus ForceType is often more practical.


16. Where Should .htaccess Be Placed?

A .htaccess file applies to the directory in which it is located and usually its children.

For example:

public_html/
├── .htaccess
├── index.php
└── downloads/
    ├── file.zip
    └── archive.zip.001

Rules in:

public_html/.htaccess

may affect the entire website.

But you can create another file:

public_html/downloads/.htaccess

containing rules specifically for downloads.

This is often preferable because it limits the configuration to the directory that actually needs it.


17. Why Limiting .htaccess Rules Is a Good Idea

Imagine adding:

ForceType application/octet-stream

to the root of a website without restricting it.

Suddenly Apache might start treating:

  • HTML pages;
  • CSS;
  • JavaScript;
  • images;

as generic downloads.

The website could stop displaying correctly.

For that reason, rules should normally be as specific as possible.

For example:

<FilesMatch "\.zip\.[0-9]{3}$">
    ForceType application/octet-stream
</FilesMatch>

is much safer.


18. What Is Nginx?

Nginx, pronounced roughly as “engine-x”, is another extremely popular web server.

It is known for:

  • high performance;
  • efficient static file delivery;
  • reverse proxying;
  • load balancing;
  • handling large numbers of concurrent connections.

Many websites use Nginx instead of Apache.

Others use both.


19. Nginx Does Not Use .htaccess

This is one of the most important differences beginners need to know.

Nginx does not read .htaccess files.

If your website runs purely on Nginx, adding:

.htaccess

will normally do absolutely nothing.

Nginx configuration is usually stored in server configuration files such as:

/etc/nginx/nginx.conf

or:

/etc/nginx/sites-enabled/example.conf

The exact location depends on the operating system and hosting setup.


20. The Nginx Equivalent

A simplified Nginx rule might look like:

location ~* \.zip\.[0-9]{3}$ {
    default_type application/octet-stream;
    add_header Content-Disposition "attachment";
}

This tells Nginx to treat matching files as downloadable binary content.

After changing Nginx configuration, an administrator would normally validate it:

nginx -t

and then reload Nginx:

systemctl reload nginx

On managed hosting, however, users may not have access to these commands.


21. Apache and Nginx Can Be Used Together

Many hosting environments use both servers.

A common configuration looks like:

Internet
   ↓
Nginx
   ↓
Apache
   ↓
PHP / WordPress

Nginx may act as:

  • a reverse proxy;
  • an SSL terminator;
  • a static file server;
  • a caching layer.

Apache may then process WordPress and PHP.

This can make troubleshooting slightly confusing.

You may add the correct rule to .htaccess, but if Nginx serves the file directly before Apache sees the request, the .htaccess rule may never be used.


22. How Can You Tell Which Web Server You Are Using?

One easy test is to inspect the HTTP response headers.

From Linux, macOS, or Windows with curl, run:

curl -I https://example.com/file.zip

You might see:

HTTP/2 200
server: nginx
content-type: application/zip
content-length: 1234567

Or:

Server: Apache

However, this is not definitive.

A reverse proxy, CDN, or hosting platform may hide the actual backend server.


23. Useful curl Commands for Troubleshooting

curl is extremely useful for checking download problems.

Show headers only

curl -I https://example.com/download/file.bin

Look for:

Content-Type
Content-Disposition
Content-Length
Server

Show headers and follow redirects

curl -IL https://example.com/download/file.bin

The -L option follows redirects.

This is useful because a file may first redirect through:

  • HTTPS enforcement;
  • a CDN;
  • authentication;
  • WordPress;
  • another domain.

Download the file

curl -O https://example.com/download/file.bin

-O saves the file using the remote filename.


24. Checking Headers in Your Browser

Modern browsers also allow you to inspect headers.

In Chrome, Edge, Firefox, and similar browsers:

  1. Open Developer Tools.
  2. Open the Network tab.
  3. Load the file.
  4. Select the request.
  5. View Response Headers.

You may see:

content-type: application/octet-stream
content-disposition: attachment
content-length: 4739201

This is often the fastest way to understand why the browser behaves a certain way.


25. MIME Type Problems and WordPress

WordPress introduces another layer.

There are two different situations.

File served directly by the web server

Example:

https://example.com/wp-content/uploads/file.zip

In many configurations, Nginx or Apache serves this file directly.

WordPress PHP code may not be involved at all.


File served through PHP

A plugin or custom script may instead generate the download.

For example:

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="download.bin"');

readfile($file);

In this case, PHP controls the HTTP headers.

Editing .htaccess may therefore not solve the problem.


26. PHP Can Also Force Downloads

A simple PHP download script might look like:

<?php

$file = '/path/to/archive.bin';

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Length: ' . filesize($file));

readfile($file);
exit;

This gives PHP full control over how the browser receives the file.

However, for very large files, directly serving the file through Nginx or Apache is usually more efficient.


27. Why You Should Not Use PHP for Every Large Download

PHP is excellent for dynamic applications.

It is not always the best tool for transferring multi-gigabyte files.

If PHP reads and sends the entire file, the download may consume:

  • PHP workers;
  • memory;
  • execution time;
  • server resources.

Static web servers such as Nginx and Apache are generally better at delivering large files directly.

For protected downloads, techniques such as:

X-Sendfile

or:

X-Accel-Redirect

can allow PHP to authorize the request while the web server performs the actual file transfer.


28. What Is application/octet-stream?

This MIME type deserves special attention.

application/octet-stream

means generic binary data.

It does not tell the browser exactly what application should open the file.

Instead, it essentially says:

“Treat this as raw binary data.”

It is commonly used for:

  • unknown file types;
  • proprietary formats;
  • archive fragments;
  • binary backups;
  • firmware files;
  • files intended purely for download.

29. Does application/octet-stream Guarantee a Download?

Not absolutely.

Browsers ultimately control their own behavior.

However, combining:

Content-Type: application/octet-stream

with:

Content-Disposition: attachment

is a strong and standard way to request download behavior.


30. What Is MIME Sniffing?

Browsers sometimes try to determine the real file format by looking at the contents.

This behavior is known as:

MIME sniffing

For example, a server may say:

Content-Type: text/plain

but the browser might inspect the first bytes and realize that the response looks like HTML.

This historically helped websites with badly configured servers.

Unfortunately, MIME sniffing can also create security problems.


31. The X-Content-Type-Options Security Header

Websites can tell browsers not to guess MIME types by sending:

X-Content-Type-Options: nosniff

This is generally considered a useful security header.

For example:

X-Content-Type-Options: nosniff

tells the browser:

Respect the declared MIME type rather than trying to reinterpret the file.

This makes correct server configuration even more important.

If the server declares the wrong MIME type, the browser is less likely to compensate for the mistake.


32. MIME Types and Website Security

Incorrect MIME types are not only inconvenient.

They can sometimes create security risks.

Imagine a file uploaded by a user that contains HTML or JavaScript.

If the server returns it with an executable web MIME type, the browser might interpret the content rather than simply downloading it.

Secure upload systems should therefore consider:

  • allowed extensions;
  • actual file content;
  • MIME types;
  • storage location;
  • response headers;
  • permissions.

Never assume that checking only the filename is sufficient security.


33. MIME Types for CSS and JavaScript Matter Too

Incorrect MIME types can break websites.

Imagine a stylesheet served as:

Content-Type: text/plain

instead of:

Content-Type: text/css

Some browsers may refuse to apply it.

Likewise JavaScript should have an appropriate MIME type.

A browser console might report an error similar to:

Refused to execute script because its MIME type is not executable.

This is particularly common when:

X-Content-Type-Options: nosniff

is enabled.


34. How Apache Knows MIME Types

Apache commonly uses the mod_mime module.

Its configuration maps extensions to MIME types.

A system MIME database may contain entries similar to:

text/html html htm
image/jpeg jpeg jpg
application/pdf pdf
application/zip zip

Apache looks at the filename extension and applies the configured type.

You can supplement these mappings using .htaccess if your hosting provider permits it.


35. How Nginx Knows MIME Types

Nginx commonly loads MIME mappings from a file called:

mime.types

A configuration may include:

http {
    include mime.types;
}

Inside mime.types, entries may resemble:

types {
    text/html       html htm;
    text/css        css;
    image/jpeg      jpeg jpg;
    application/pdf pdf;
    application/zip zip;
}

For unknown extensions, Nginx uses its configured default type.

A common default is:

default_type application/octet-stream;

36. What About Files With Multiple Extensions?

Consider:

database.backup.gz

or:

archive.tar.gz

or:

largefile.zip.001

Which extension matters?

That depends on the server and its configuration.

A server may recognize:

.gz

but not:

.001

For:

largefile.zip.001

the final extension is normally:

.001

Therefore, the server may not automatically recognize it as part of a ZIP archive.

This is why custom MIME rules can be useful.


37. Split ZIP Archives Explained

Large archives are sometimes divided into smaller parts:

backup.zip.001
backup.zip.002
backup.zip.003

Each individual file is only part of the full archive.

Downloading one part alone normally does not produce a complete ZIP file.

All pieces must usually be downloaded into the same directory.

Extraction is then started from the first part:

backup.zip.001

Software such as 7-Zip can normally reconstruct the archive using the remaining pieces automatically.


38. Do Not Rename Split Archive Parts Arbitrarily

Suppose you have:

archive.zip.001
archive.zip.002
archive.zip.003

Renaming:

archive.zip.003

to:

archive.zip

does not magically create a valid archive.

The file contains only a portion of the complete data.

The parts need to remain together and in the correct order.


39. Content-Length and Downloads

Another useful HTTP header is:

Content-Length

Example:

Content-Length: 84572913

This tells the browser how many bytes the server intends to send.

It helps browsers:

  • display download progress;
  • estimate completion percentage;
  • detect incomplete transfers.

A missing Content-Length does not necessarily indicate a problem because HTTP can also use chunked transfer encoding.


40. Range Requests and Resumable Downloads

For large downloads, another useful feature is HTTP range support.

A server may return:

Accept-Ranges: bytes

This allows a client to request only part of a file.

For example:

Range: bytes=1000000-

Range requests allow:

  • paused downloads;
  • resumed downloads;
  • download managers;
  • media seeking.

Apache and Nginx normally support byte ranges for static files.


41. What Is a 206 Partial Content Response?

When a client requests only part of a file, the server may answer:

HTTP/1.1 206 Partial Content

and include:

Content-Range: bytes 1000000-1999999/8000000

This is normal.

It does not mean that the server failed.

It simply means the server returned the requested portion of the file.


42. Why Downloads Sometimes Become Corrupted

If a downloaded file genuinely is corrupted, several causes are possible.

Examples include:

  • interrupted upload;
  • incomplete FTP transfer;
  • disk corruption;
  • server-side modification;
  • PHP output being inserted before binary data;
  • antivirus or security proxy interference;
  • incomplete multipart archive;
  • incorrect transfer mode in very old FTP software.

MIME types themselves generally do not change the underlying bytes of a static file.

They mainly tell the browser how to interpret those bytes.


43. How to Verify That a File Was Downloaded Correctly

A strong method is to compare cryptographic hashes.

On Linux:

sha256sum archive.zip.001

On Windows PowerShell:

Get-FileHash archive.zip.001 -Algorithm SHA256

You might obtain:

A5199D6F...

Run the same calculation on the original file.

If both SHA-256 hashes are identical, the files are byte-for-byte identical.


44. Download Problems Caused by CDNs

Modern websites may use a CDN such as:

  • Cloudflare;
  • Fastly;
  • Akamai;
  • Bunny;
  • Amazon CloudFront.

The request path may therefore look like:

Browser
   ↓
CDN
   ↓
Nginx
   ↓
Apache
   ↓
Application

The CDN may:

  • cache headers;
  • modify compression;
  • serve cached copies;
  • apply content rules.

After changing the origin server configuration, you may need to purge the CDN cache before seeing the new behavior.


45. Browser Cache Can Also Mislead You

Browsers may cache:

  • response bodies;
  • redirects;
  • MIME types;
  • headers.

After changing server configuration, test using:

  • a private/incognito window;
  • Developer Tools with cache disabled;
  • curl;
  • another browser.

This helps distinguish a server problem from a stale browser cache.


46. Apache .htaccess Errors and HTTP 500

Incorrect .htaccess syntax can cause:

500 Internal Server Error

For example, a directive may require an Apache module that is unavailable.

If:

Header set Content-Disposition "attachment"

causes an error, the mod_headers module may not be enabled or allowed.

You could temporarily test:

<FilesMatch "\.bin$">
    ForceType application/octet-stream
</FilesMatch>

If the website works again, the Header directive may have been the issue.


47. .htaccess May Be Disabled

Apache administrators can control whether .htaccess files are allowed using AllowOverride.

For example:

AllowOverride None

means .htaccess rules are ignored.

Whereas configurations such as:

AllowOverride All

permit many .htaccess directives.

On shared hosting, this is controlled by the hosting provider.


48. Why Nginx Avoids .htaccess

Apache may search directories for .htaccess files while processing requests.

Nginx uses a different philosophy.

Its configuration is normally loaded centrally when the server starts or reloads.

This provides:

  • predictable configuration;
  • less per-request filesystem checking;
  • centralized administration.

The disadvantage is that ordinary users cannot usually change Nginx settings simply by uploading an .htaccess file.


49. WordPress .htaccess Should Be Edited Carefully

A standard WordPress Apache configuration often includes rules similar to:

# BEGIN WordPress

RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]

# END WordPress

WordPress may regenerate portions between:

# BEGIN WordPress

and:

# END WordPress

For custom rules, it is usually safer to place them outside automatically managed sections unless you know exactly how your setup behaves.


50. A Dedicated Download Directory Is Often Better

Instead of scattering large files throughout a website, consider using:

/downloads/

For example:

public_html/
└── downloads/
    ├── .htaccess
    ├── package.zip.001
    ├── package.zip.002
    └── package.zip.003

The directory can then have its own download configuration.

Example Apache configuration:

<FilesMatch "\.(zip|7z|rar|bin)$">
    ForceType application/octet-stream
    Header set Content-Disposition "attachment"
</FilesMatch>

<FilesMatch "\.zip\.[0-9]{3}$">
    ForceType application/octet-stream
    Header set Content-Disposition "attachment"
</FilesMatch>

This keeps download rules separate from the rest of the website.


51. Protecting a Download Directory

If files should not be publicly discoverable, remember that MIME configuration is not access control.

These lines:

ForceType application/octet-stream
Header set Content-Disposition "attachment"

do not protect the file.

Anyone who knows the URL may still download it.

Access protection requires something else, such as:

  • authentication;
  • signed URLs;
  • application-level authorization;
  • IP restrictions;
  • expiring links;
  • private object storage.

52. Do Not Confuse MIME Types With File Permissions

Linux file permissions such as:

644
755
600

control whether the operating system allows users or processes to access files.

MIME types control how HTTP clients interpret responses.

These are completely different concepts.

For example:

644

does not mean:

application/zip

and changing permissions will not normally fix an incorrect Content-Type.


53. MIME Type vs File Signature

A file extension says what someone claims the file is.

A MIME type says what the server claims the file is.

A file signature, sometimes called a magic number, gives clues about what the file actually contains.

For example, ZIP files commonly start with bytes corresponding to:

PK

PDF files normally begin with:

%PDF

PNG images begin with a defined binary signature.

Security software often checks these signatures rather than trusting filenames alone.


54. Why Upload Validation Should Not Trust MIME Types Alone

Suppose someone uploads:

photo.jpg

but the file actually contains executable or HTML content.

Checking only:

.jpg

is insufficient.

Likewise, browser-supplied MIME information can sometimes be forged.

Good upload validation may examine:

  • extension;
  • MIME type;
  • file signature;
  • file size;
  • allowed format;
  • storage location.

55. Compression Is Different From MIME Type

Another common source of confusion is:

Content-Encoding: gzip

This is not the same thing as:

Content-Type: application/gzip

Content-Type tells the browser what the resource is.

Content-Encoding tells the browser how the resource has been encoded for transport.

For example:

Content-Type: text/css
Content-Encoding: gzip

means:

This is a CSS file that has been compressed with gzip for transmission.

The browser decompresses it automatically.


56. Common HTTP Headers Worth Knowing

When diagnosing file downloads, these are especially useful:

Content-Type
Content-Disposition
Content-Length
Content-Encoding
Accept-Ranges
Content-Range
Cache-Control
ETag
Last-Modified
Server
Location

You do not need to memorize all of them.

For download problems, start with:

Content-Type
Content-Disposition

Those two explain a large percentage of browser behavior.


57. A Practical Troubleshooting Checklist

If clicking a file produces strange browser output instead of a download, work through these steps.

Step 1: Check the file on the server

Confirm that:

  • the upload completed;
  • the file size is correct;
  • the filename is correct.

Step 2: Inspect the HTTP headers

Run:

curl -I https://example.com/path/file

Step 3: Check Content-Type

For an unknown binary file, something like this is usually appropriate:

application/octet-stream

Step 4: Check Content-Disposition

For a forced download:

attachment

Step 5: Determine the web server

Check whether the site uses:

  • Apache;
  • Nginx;
  • both;
  • a CDN.

Step 6: Apply the rule in the correct layer

Apache:

.htaccess

may work.

Nginx:

.htaccess

will not work.

Step 7: Clear caches

Check:

  • browser cache;
  • WordPress cache;
  • reverse proxy cache;
  • CDN cache.

Step 8: Test again

Use:

curl -I

instead of relying only on browser behavior.


58. Example: Correct Headers for an Ordinary ZIP File

A normal ZIP download might return:

HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="package.zip"
Content-Length: 82938122
Accept-Ranges: bytes

This clearly tells the browser what the file is and that it should be downloaded.


59. Example: Correct Headers for an Unusual Binary Part

A split archive component might instead use:

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Disposition: attachment
Content-Length: 104857600
Accept-Ranges: bytes

This is perfectly reasonable because a file such as:

package.zip.017

does not need a specialized MIME type.


60. Common Beginner Mistakes

Several mistakes appear repeatedly when troubleshooting this problem.

Mistake 1: Assuming the file is corrupted because the browser displays garbage

Binary data displayed as text naturally looks like garbage.

Mistake 2: Renaming an archive fragment

A split archive part cannot normally become a complete archive by changing its filename.

Mistake 3: Adding .htaccess rules to an Nginx-only server

Nginx ignores .htaccess.

Mistake 4: Changing MIME types globally

A rule intended for downloads may accidentally affect the entire website.

Mistake 5: Forgetting CDN caching

The origin may be fixed while the CDN continues serving old headers.

Mistake 6: Confusing MIME type with security

application/octet-stream does not make a file private.

Mistake 7: Using PHP unnecessarily for large files

Static delivery through the web server is usually much more efficient.


61. Apache or Nginx: Which Is Better?

There is no universal winner.

Apache is popular because it is:

  • mature;
  • flexible;
  • widely supported;
  • compatible with .htaccess;
  • convenient for shared hosting.

Nginx is popular because it is:

  • efficient;
  • fast at serving static files;
  • excellent as a reverse proxy;
  • suitable for high-concurrency workloads.

Many production platforms use both.

The important point is not which one is “better.”

The important point is knowing which server is responsible for the response you are troubleshooting.


62. The Most Important Concept to Remember

When you request a file from a website, the browser does not receive only the file.

It receives:

HTTP headers
+
file data

The headers describe how the data should be interpreted.

A perfectly valid binary file combined with incorrect headers can appear completely broken.

For example:

Correct binary file
+
Content-Type: text/plain
=
browser displays strange characters

while:

Correct binary file
+
Content-Type: application/octet-stream
+
Content-Disposition: attachment
=
browser downloads the file

The underlying file may be identical in both cases.


Conclusion

MIME types are one of those web technologies that remain invisible until something goes wrong.

When everything is configured properly, clicking a PDF opens a PDF, clicking an image shows an image, and clicking an archive downloads an archive.

Behind that apparently simple behavior are several important components:

  • file extensions;
  • MIME types;
  • HTTP Content-Type;
  • Content-Disposition;
  • Apache;
  • Nginx;
  • .htaccess;
  • PHP;
  • reverse proxies;
  • CDNs;
  • browser behavior.

For beginners, the most useful diagnostic command to remember is:

curl -I https://example.com/file

Then look first at:

Content-Type
Content-Disposition

If a binary file is being displayed as unreadable characters, there is a good chance that nothing is wrong with the data itself.

The browser may simply have received the wrong instructions.

And once you know which server is sending those instructions, fixing the problem is usually much easier.


Frequently Asked Questions

What MIME type should I use for an unknown downloadable file?

A common choice is:

application/octet-stream

For download behavior, it can be combined with:

Content-Disposition: attachment

Can .htaccess configure Nginx?

No. Nginx does not process .htaccess files.

Does seeing strange characters mean my ZIP file is corrupt?

Not necessarily. A binary file displayed as text naturally looks like unreadable characters.

What header forces a browser to download a file?

Usually:

Content-Disposition: attachment

What header tells the browser what kind of file it received?

Content-Type

What does application/octet-stream mean?

It represents generic binary data and is commonly used for files intended for download.

Can WordPress control MIME types?

Yes, in some situations. However, static files in directories such as wp-content may be delivered directly by Apache, Nginx, or a CDN without WordPress PHP being involved.

Why did my .htaccess change have no effect?

Possible reasons include:

  • the server uses Nginx;
  • Apache has disabled .htaccess;
  • Nginx serves the file before Apache;
  • a CDN cached the old response;
  • the matching rule is incorrect;
  • another configuration overrides the header.

How do I check what MIME type a server is returning?

Use:

curl -I https://example.com/file

and inspect the Content-Type response header.

Is changing the MIME type enough to secure a download?

No. MIME types control how content is interpreted. Authentication and authorization are separate security mechanisms.

This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back