Apache Config and .htaccess Formatter

Paste an .htaccess file or a VirtualHost definition to indent every section by depth, tidy directive spacing and find the tag that was never closed.

Input

Settings

History

Load from URL

Where Apache configuration lives

Apache httpd reads its settings from httpd.conf or apache2.conf, from per-site files in sites-available, and from .htaccess files dropped into any web directory. That last one is the file most developers actually edit: WordPress permalinks, Laravel’s public/.htaccess, single-page-app fallbacks, HTTPS redirects and cache headers all live there, frequently on shared hosting where it is the only config you are allowed to touch. The syntax is line based. Each line is one directive, such as RewriteRule or Header set, and container sections like <VirtualHost>, <Directory>, <IfModule>, <FilesMatch> and <If> wrap groups of directives in XML-like opening and closing tags.

How to use it

Paste the configuration or drop the file onto the input. Section tags such as <VirtualHost> or directives like RewriteEngine and DocumentRoot identify it as Apache config. The output follows your edits live; use Ctrl/Cmd+Enter to reformat explicitly, and Ctrl/Cmd+Shift+C to put the result on the clipboard.

Choose 2 spaces, 4 spaces or tabs with Indent in the toolbar; that is the only setting, because the rest of the style follows from the structure of the file. The built-in Apache config printer processes everything inside your browser, which is worth knowing when the file contains basic-auth paths, internal proxy targets or IP allow-lists.

How the output is laid out

  • Every directive inside a section is indented one level per enclosing section, so a RewriteRule inside <IfModule> inside <VirtualHost> sits two levels in.
  • Closing tags line up with their opening tags. Apache matches section names without regard to case, and so does the formatter; a mismatched-case closer such as </DIRECTORY> is rewritten to the spelling of its opening tag.
  • Runs of spaces and tabs between arguments shrink to a single space, which straightens out hand-aligned ProxyPass and SSLCertificateFile columns. Quoted arguments such as "^/a b$" or a Header set value keep their inner spacing.
  • Directive names keep their case. rewriteengine on is valid for Apache, and it is not rewritten.
  • Comments are indented with the lines around them. Blank lines are kept as separators, collapsed to one, and dropped directly after an opening tag or before a closing one.
  • A directive continued onto the next line with a trailing backslash, common for long LogFormat and Header values, keeps its line breaks; the continuation is indented one extra level. If a quoted string itself spans the break, those lines are left exactly as written so the whitespace inside the quotes is not altered.

Checks before you upload

A broken .htaccess takes the whole directory down with a 500 Internal Server Error, so structure is checked before anything is printed. The formatter reports a section that is never closed, a closing tag with no opening partner, sections closed in the wrong order, and a section tag missing its >, each with the line number. It does not check directive names, arguments or whether the module behind an <IfModule> is loaded. apachectl configtest (or apache2ctl -t) remains the final word on a server you control.

Examples

.htaccess for a single-page app

Rewrite rules are indented inside their IfModule, and the FilesMatch section nests a level deeper with its quoted regex untouched.

Input
# .htaccess for a single-page app
Options -MultiViews
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(css|js|woff2)$">
Header set Cache-Control "max-age=31536000, immutable"
</FilesMatch>
</IfModule>
Output
# .htaccess for a single-page app
Options -MultiViews
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>
<IfModule mod_headers.c>
  <FilesMatch "\.(css|js|woff2)$">
    Header set Cache-Control "max-age=31536000, immutable"
  </FilesMatch>
</IfModule>
Open this example in the tool

HTTPS VirtualHost with column-aligned directives

Mixed tabs and spaces become a consistent indent, padded columns collapse to single spaces, and ${APACHE_LOG_DIR} is preserved.

Input
<VirtualHost *:443>
    ServerName   shop.example.com
	ServerAlias  www.shop.example.com
SSLEngine on
SSLCertificateFile      /etc/letsencrypt/live/shop.example.com/fullchain.pem
SSLCertificateKeyFile   /etc/letsencrypt/live/shop.example.com/privkey.pem
ProxyPreserveHost On
ProxyPass        /api http://127.0.0.1:8080/api
ProxyPassReverse /api http://127.0.0.1:8080/api
<Location /admin>
Require ip 10.0.0.0/8
</Location>
ErrorLog ${APACHE_LOG_DIR}/shop-error.log
</VirtualHost>
Output
<VirtualHost *:443>
  ServerName shop.example.com
  ServerAlias www.shop.example.com
  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/shop.example.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/shop.example.com/privkey.pem
  ProxyPreserveHost On
  ProxyPass /api http://127.0.0.1:8080/api
  ProxyPassReverse /api http://127.0.0.1:8080/api
  <Location /admin>
    Require ip 10.0.0.0/8
  </Location>
  ErrorLog ${APACHE_LOG_DIR}/shop-error.log
</VirtualHost>
Open this example in the tool

Continued LogFormat and a lowercase closing tag, 4-space indent

The LogFormat keeps its backslash continuation, and </files> is printed as </Files> to match the opening tag.

Input
LogFormat "%h %l %u %t \"%r\" %>s %b" \
    common
<Files ".env">
Require all denied
</files>
Output
LogFormat "%h %l %u %t \"%r\" %>s %b" \
    common
<Files ".env">
    Require all denied
</Files>
Open this example in the tool

Common errors and how to fix them

ErrorCauseFix
Section <VirtualHost> opened on line 1 is never closedA container section has no closing tag, often because the paste stopped before the end of the file.Add </VirtualHost> after the last directive that belongs inside it.
Closing tag </Directory> on line 1 has no matching opening tagA closing tag appears without its opening tag above it, typically after part of a block was deleted.Remove the orphaned closing tag or restore the <Directory …> line it belongs to.
Expected </Directory> (opened on line 1) but found </Files> on line 2Sections are closed in the wrong order, or the inner section was never closed before the outer one ends.Close the innermost open section first; Apache requires sections to nest strictly.
Section tag on line 1 is missing its closing '>'An opening tag such as <Directory /var/www was not finished with >, so Apache cannot tell where its arguments end.Add ‘>’ at the end of the tag.
Malformed closing tag on line 3A closing tag contains extra text, as in </Directory /var/www>. Closing tags take no arguments.Reduce it to the bare name, for example </Directory>.

Frequently asked questions

Can I format a WordPress or Laravel .htaccess file?

Yes. The # BEGIN WordPress markers and other comments are kept, rewrite rules keep their exact patterns and flags, and only indentation and spacing change.

Will the formatter fix a 500 Internal Server Error?

It finds structural causes such as an unclosed <IfModule> or mismatched tags. Errors from a misspelt directive or a module that is not installed are only visible in the Apache error log.

Does it change RewriteRule patterns or flags?

No. Arguments are copied character for character; only the whitespace between them is reduced to single spaces.

Can I convert Apache config to nginx here?

No. The two formats work differently, especially for rewrites, so a conversion needs manual review. The nginx formatter can tidy the result once you have written it.

Related tools