4 web server rules you need today

This post uses Apache examples but I’ve also provided links to Nginx documentation as these two web servers account for about two-thirds of websites at the time of this post. The concepts are similar between web servers with variance in syntax and location of web server rules.

Not sure which web server your site is running? Check this web server utility.

colorful feather logo of Apache web server

What are web server rules?

Web server rules are instructions for the web server, directing it what to do with requests to your website like loading an image, redirecting a URL, denying access to content and serving error messages.

We’ll be reviewing the following web server rules:

  1. Redirect a single page request
  2. Redirect from one file path to another
  3. Turn off directory browsing
  4. Add custom error pages

Apache web server rules live in an .htaccess file located in the website’s root directory. If an .htaccess file doesn’t already exist, you can create one using a code editor and upload it to your web server. The file must start with the . character and does not have a file extension.

Web servers respond to each browser request with a code. The most common response is a 200 which means the request is successful and the web server responds by serving up the requested content like an HTML page, image or CSS file. Each rule starts on a new line.

You can see the total number of requests each webpage makes by opening developer tools in your browser (F12) and looking at the “Network” tab as you request a URL.

screen shot of the network tab in Firefox developer tools displaying 6 200 responses to content requested for a page on domain
Network tab in Firefox developer tools

Redirect a single page request

Web server Redirect rules generally respond with either 301 (permanent redirect) or 302 (temporary redirect). The following redirect rule returns a 302 response to the browser:

Redirect 302 /story-slides/index.html /talks/

Instead of loading the requested URL, the web server redirects automatically to

Network tab in developer tools displaying a 302 response to domain request and the 200 response after redirect.
302 redirect from one page to another

How To Create Temporary and Permanent Redirects with Nginx

NOTE: 301 permanent redirects get cached by the browser and can be very hard to clear. Always create and test 302 redirects, changing to 301 once you’ve tested the rule is working correctly.

Redirect from one file path to another

What if you want to redirect all requests for a site or directory? When I consolidated my blog with this website, I set up the following RewriteRule rule on the old domain:

RewriteRule ^(.*)$$1 [R=302,NC,L]

Requests for posts on the old domain are sent to the new-domain/blog/the-requested-file-path/.


Network tab in developer tools displaying a 302 response to domain request and the 200 response after redirect.
302 redirect from old domain to new domain

Creating NGINX Rewrite Rules

Turn off directory browsing

Any website directory that doesn’t load a default web page may list its contents instead. Have you tried going to your images directory? You might see something like this:

a default directory listing of image files
Files in the /images directory

Add this directive to your .htaccess file and the server will block directory browsing:

Options -Indexes

The browser now returns a 403 code, access to the requested resource is forbidden.

Web page and network tab in developer tools displaying a 403 response
403 browser response

Nginx – Disable directory listing

Add custom error pages

Web servers are setup with default error pages for some response codes like 403 and 404. Give your site that finishing touch with custom error pages. Add a directive for each error code you want to customize:

ErrorDocument 404 /404/

Include the response code and the page that should load instead.


Web page and network tab in developer tools displaying a 404 response - page not found
Custom 404 error page on

How To Create Custom 404 Page in NGINX

Have any questions or comments? Hit me up on Twitter.

What do you mean by disabled?

A truck engine bay with most of the engine torn out.

For much of the 20th century and into the 21st, society largely dictated what “disabled” meant. We were told we were disabled; that we were broken; that we didn’t matter because we weren’t whole. “Disabled” in this context is clearly used as an adjective to describe that state of a person: You’re disabled.

Indeed, if we search the dictionary for disabled, the first result is the adjective form: impaired or limited by a physical, mental, cognitive, or developmental condition : affected by disability.

As a backlash to being told we were non-functional—the medical model and ableist view of disability—some people switched to person-first language. It was thought that if you center the person instead of their disability, we were respecting people with disabilities. In short, the opposite proved to be true. The concept of disability became clouded; some people, like members of the Deaf community, don’t view their condition as disabling. For others, disability is an important part of self-identification and that got lost.

In the last few years, this has led to the disabled community taking back the word “disabled” to describe themselves, but with one very important distinction: the word is no longer used as an adjective but in its other form as a verb.

If we search the dictionary for disable, we note that its past participle is “disabled.” This is the basis for the passive voice instead of an adjective in the sentence, “I’m disabled.” We know it’s passive voice because you can add “by zombies” to the end. But passive voice has the annoying habit of obscuring the real actor.

I’m disabled by society and the built environment.

Rachele DiTullio

It’s important that those outside the disability community understand what we mean when we use “disabled” versus what they might mean. I encourage you to let them know you are fine just as you are. You are not disabled as in broken. You are forced to live in a world that disables you through intentional action, by not making society inclusive and accessible.

What do you think? Adjective or verb? Let me know on Twitter.

Structuring accessible forms

On 28 September 2021, I was a guest on Ben Myer’s Twitch stream where we demonstrated best practices for structuring accessible forms. Following is the example code and an explanation of what we covered.

See the Pen Accessible Forms by Rachele (@racheleditullio) on CodePen.

Creating our form fields

The two basic parts of a form field are its <label> and <input> elements. We semantically link the two by

  • Using the <label for="uniqueID"> attribute which matches the <input id="uniqueID"> attribute; or
  • Making the <input> element a child of the <label> element

Doing so allows screens readers to announce the field’s <label> when the <input> gets focus. It also enables the <label> as an additional hit area when using the mouse to focus on an <input>, which is especially useful for checkboxes and radio buttons.

We also need to specify the type of input using the <input type=""> attribute. Putting those together, we have a basic form with one text field and two radio buttons.

  <label for="name">Cat's name</label>
  <input type="text" id="name" name="name">

  <label><input type="radio" id="yes"> Yes</label>
  <label><input type="radio" id="no"> No</label>

  <button type="submit">Send</button>

A note on combo boxes

As much as possible, use native HTML <select> and <option> elements to create an expandable list of single-select options.

<label for="markings">Cat's markings</label>
<select name="markings" id="markings">
  <option value=""> select an option </option>
  <option value="solid">Solid</option>
  <option value="bi">Bi-color</option>

Grouping similar fields

Our radio buttons are labeled ‘yes’ and ‘no,’ but what are they for? We need to use the <fieldset> and <legend> elements to provide that semantic meaning. The <fieldset> groups the related form fields while the <legend> provides a name for the grouping. These are most often used for checkboxes and radio buttons but they can be useful for grouping other related fields, e.g. Shipping address.

Since radio button options may have similar names, group like radio buttons with the name="groupName" attribute. Keyboard users move between radio buttons in a group with the arrow keys.

  <legend>Is your cat altered?</legend>
    <label><input type="radio" name="altered" id="yes"> Yes</label>
    <label><input type="radio" name="altered" id="no"> No</label>

Marking required fields

Let’s create a required field for collecting email address with <input type="email">. Provide a visible indication of the required field for sighted users, such as an asterisk, but hide it from assistive technology using the aria-hidden="true" attribute.

Then there are two attributes we can use to programmatically define required fields: aria-required="true" and required.

Use one (not both) of these attributes to ensure required fields are conveyed appropriately to assistive technology. Screen readers will say required when announcing the form field name, role and state.

<label for="email">Your email<span aria-hidden="true">*</span></label>
<input type="email" id="email" name="email" aria-required="true">

The required attribute provides a first layer of form validation on submit. Many modern browsers will not submit a form with empty required fields and will even provide a visible error message.

a requried field in a web form that is empty and displays the message please fill out this form field.
Required field in Firefox for Windows

However, user agent error handling is not dependable as these error messages are not always announced or available to assistive technology; they can’t be styled or resized; and they are not persistent.

Handling errors

It’s important to provide a list of all errors at the top of the form or provide them in-context of the field in error. We can programmatically link the error message with the form field using the aria-describedby attribute.

<input type="email" id="email" name="email" aria-required="true" aria-describedby="error-email">
<p id="error-email">Email format</p>

When assistive technology users focus on the email field, the error message is announced along with the name, role and state of the field.

Verifying data

In addition to marking fields as required for assistive technology, we also have to indicate if the data entered into each field is valid. All required fields should also include the aria-invalid="true" attribute. Update this to “false” when it passes validation.

It’s also an accessibility requirement to make entering valid data as easy as possible. HTML has a set of autocomplete values that we need to use for any fields collecting personal information that might already be stored in the user’s browser. Email is one of these fields.

<input type="email" id="email" name="email" aria-required="true" aria-describedby="error-email" aria-invalid="true" autocomplete="email">

We can further enforce data validation in HTML for fields that aren’t necessarily required by using the pattern attribute that accepts a regular expression. Let’s create a field for collecting birthday with a required format of mm/dd/yyyy.

<input type="text" id="birthday" name="birthday" aria-describedby="help1" pattern="^\s*(1[012]|0?[1-9])\/(3[01]|[12][0-9]|0?[1-9])\/((?:19|20)\d{2})\s*$">
<p id="help1">Birthday format mm/dd/yyyy</p>

This pattern matching prevents the form from submitting if the data entered does not match the specified pattern.


I hope you found something to make your forms more accessible. I like forms because they have such a strong semantic structure. There are a lot of things to get right but it’s pretty straightforward what “right” means in this context: Make sure anything that is conveyed visually is also conveyed to assistive technology, including the states of form fields.