Redirect HTTP to HTTPS with .htaccess (301 redirect)
Visitors still landing on the unencrypted page? A few lines in the .htaccess file are enough to redirect every HTTP request permanently to HTTPS with a 301 redirect.
Your server already delivers the website over HTTPS, but visitors still end up on the unencrypted HTTP version? Then a redirect is missing. In this guide you set up a permanent redirect (status code 301) from HTTP to HTTPS with an .htaccess file.
A 301 redirect is also the right choice from an SEO point of view: search engines transfer the rankings of the old HTTP address to the HTTPS address instead of treating both variants as separate pages.
Requirements
- Your server runs Apache. nginx uses a different configuration, more on that further below.
- A valid SSL certificate is already in place. If not, you'll find the matching guide in the article Set up a free SSL certificate with Let's Encrypt.
- You have access to the web directory of your server, either via SSH or via FTP.
Important: only set up the redirect once HTTPS actually works. Otherwise you send visitors to an address that greets them with a certificate warning.
Enable mod_rewrite and allow .htaccess
The redirect relies on the Apache module mod_rewrite. Enable it and restart Apache:
a2enmod rewrite
systemctl restart apache2
For Apache to read the .htaccess file at all, the VirtualHost has to permit it. Check the configuration under /etc/apache2/sites-available/ to see whether AllowOverride All is set for your directory:
<Directory /var/www/MeineDomain.de>
AllowOverride All
Require all granted
</Directory>
If it says AllowOverride None there, your .htaccess file is silently ignored. After a change to the VirtualHost file, Apache needs a restart.
Create the .htaccess file
Change into the directory that holds your website:
cd /var/www/<YOUR-WEB-DIRECTORY>
Open the .htaccess file in an editor. If it does not exist yet, the command creates it:
nano .htaccess
Add the following lines. This variant checks directly whether the connection is encrypted and appends the complete requested path to the target:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Save the file with "CTRL + X", then "Y" and "Enter".
Alternative using the server port
On older configurations where the HTTPS variable is never set, checking the port works instead:
RewriteEngine On
RewriteCond %{SERVER_PORT} !^443$
RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]
Variant behind a reverse proxy or load balancer
If a reverse proxy or a load balancer sits in front of your Apache and terminates the encryption itself, the request reaches Apache unencrypted. The rule above would then redirect endlessly. In that case, evaluate the header that the proxy sends along:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Test the redirect
Open your domain in the browser over http://. You should land on https:// right away. On the command line you check the status code directly:
curl -I http://MeineDomain.de
The output has to show HTTP/1.1 301 Moved Permanently, plus a Location line with the HTTPS address. If a status code 302 appears instead, check that the rule really contains R=301.
Enable HSTS (optional)
With HTTP Strict Transport Security you tell the browser never to call your domain over HTTP again. That removes the first unsecured request. Start by enabling the required module:
a2enmod headers
systemctl restart apache2
Then add the following to the .htaccess file:
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>
Keep in mind: HSTS commits you for a full year. As long as the value is stored in the browser, the domain can no longer be reached over HTTP. Only set the header once HTTPS runs reliably and all subdomains have a valid certificate as well.
Common errors
- Redirect loop ("too many redirects"): almost always the result of a proxy in front of the server. Use the variant with
X-Forwarded-Proto. - Nothing happens: either mod_rewrite is not active, or the VirtualHost does not allow an .htaccess file (
AllowOverride None). - Error 500 after saving: a typo in the .htaccess file. The exact reason is in the Apache error log under
/var/log/apache2/error.log. - Mixed content: the page does load over HTTPS, but it still pulls in images or scripts over HTTP. Adjust those addresses in your source code or in the database.
- File not found: the .htaccess file starts with a dot and is therefore hidden.
ls -lashows it.
Redirect without .htaccess
An .htaccess file is read again on every single request. If you have access to the server configuration, it is faster to put the rules straight into the VirtualHost. For the HTTP VirtualHost this is enough:
<VirtualHost *:80>
ServerName MeineDomain.de
Redirect permanent / https://MeineDomain.de/
</VirtualHost>
If you use nginx instead of Apache, there are no .htaccess files. There you add the redirect to the server block for port 80:
server {
listen 80;
server_name MeineDomain.de www.MeineDomain.de;
return 301 https://$host$request_uri;
}
Frequently asked questions
Why a 301 redirect and not a 302?
My .htaccess file is ignored. What causes that?
Why do I end up in a redirect loop?
Does this work with nginx as well?
Should I enable HSTS on top of this?
2022-2026 KernelHost GmbH. All rights reserved. This guide is protected by copyright. Republishing it on other websites, in whole, in part or in edited form, is not permitted without our written consent. Quoting with a source credit and a link is expressly welcome.

