Apache Reverse Proxy Configuration: Accessing Applications by Subdomains

This tutorial explains how to set up an Apache reverse proxy to access different applications running on your own server using different subdomains.

Preprequisites

  • Root access (via SSH) to a Linux Server (VPS, Dedicated Server, Home Serve)
  • A domain name (free or bought)

1. Get a domain name

You can either get a free domain name from providers such as ClouDNS, or buy one, e.g. from hosting companies such as Hostinger.

2. Add CNAME DNS entries for each subdomain

Add a CNAME entry for each subdomain required. Assuming that you want to run a regular Apache website, a WordPress blog, and a Nextcloud server on the same machine, we want to point the host “blog” and “cloud” to our domain name as follows:

Example DNS configuration on Hostinger
Example CNAME entries on ClouDNS

Also make sure to select a low TTL (time to live) time which allows you to quickly change the CNAME entries of you need to. You can then set a higher TTL once you have got everything set up.

3. Setup the Apache reverse proxy

You can now add your subdomain names in the 000-default.conf file to route your subdomains to different directories or applications running on your server.

First, you simply want to add a virtual host block for the regular domain:

<VirtualHost *:80>
        ServerName yourdomain.com
        ServerAdmin webmaster@yourdomain.com
        DocumentRoot /var/www/html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

If you are running Nextcloud as a regular installation and you want to route the domain cloud.yourdomain.com to it, you need to add the following virtual host block:

<VirtualHost *:80>
        ServerName cloud.yourdomain.com
        ServerAdmin webmaster@yourdomain.com
        DocumentRoot /var/www/html/nextcloud
        <Directory /var/www/html/nextcloud/>
                Options +FollowSymlinks
                AllowOverride All
                <IfModule mod_dav.c>
                        Dav off
                </IfModule>
                SetEnv HOME /var/www/html/nextcloud
                SetEnv HTTP_HOME /var/www/html/nextcloud

                RewriteEngine On
                RewriteRule ^/\.well-known/carddav http://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
                RewriteRule ^/\.well-known/caldav http://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
                RewriteRule ^/\.well-known/host-meta http://%{SERVER_NAME}/public.php?service=host-meta [QSA,L]
                RewriteRule ^/\.well-known/host-meta\.json http://%{SERVER_NAME}/public.php?service=host-meta-json [QSA,L]
                RewriteRule ^/\.well-known/webfinger https://%{SERVER_NAME}/public.php?service=webfinger [QSA,L]
        </Directory>
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Furthermore, you need to edit the config file to allow connections to Nextcloud on the new domain:

<?php
$CONFIG = array (
...
  'trusted_domains' => 
array (
        0 => 'https://cloud.yourdomain.com',
),
);

If you are running Nextcloud as a snap instance however, the required block is slightly different. Note that in this case we use the ProxyPass and ProxyPassReverse directives to route access on the subdomain to the snap instance:

<VirtualHost *:80>
        ServerName cloud.yourdomain.com
        ServerAdmin webmaster@yourdomain.com
        ProxyPreserveHost On
        ProxyRequests Off
        RewriteEngine On
        RewriteRule ^/\.well-known/carddav http://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
        RewriteRule ^/\.well-known/caldav http://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
        RewriteRule ^/\.well-known/host-meta http://%{SERVER_NAME}/public.php?service=host-meta [QSA,L]
        RewriteRule ^/\.well-known/host-meta\.json http://%{SERVER_NAME}/public.php?service=host-meta-json [QSA,L]
        RewriteRule ^/\.well-known/webfinger http://%{SERVER_NAME}/public.php?service=webfinger [QSA,L]
        ProxyPass / http://localhost:81/
        ProxyPassReverse / http://localhost:81/
</VirtualHost>

Additionally, you must change the default port on which the nextcloud snap is running, e.g. to port 81 as we need must use port 80 to accept un-encrypted connections to our server.

sudo snap set nextcloud ports.http=81

Again, you need to add this domain to your trusted domains

<?php
$CONFIG = array (
...
  'trusted_domains' => 
array (
        0 => 'https://cloud.yourdomain.com',
),
);

Finally, if you want to link to another applications, e.g. a wiki running under port 8080 this would be the required virtual host block:

<VirtualHost *:80>
        ServerName wiki.yourdomain.com
        ServerAdmin webmaster@yourdomain.com
        ProxyPreserveHost On
        ProxyRequests Off
        ProxyPass / http://localhost:8080/
        ProxyPassReverse / http://localhost:8080/
</VirtualHost>

As a next step, I would highly recommend you to secure your traffic using an SSL certificate! Check out this follow up guide on how to set up a Free Wildcard SSL Certificate for Nextcloud and WordPress.

7 thoughts on “Apache Reverse Proxy Configuration: Accessing Applications by Subdomains”

  1. Thank you very much, it is the only description I found of explicitly for configuring specifically nextcloud snap virtual host for apache. Nonetheless after editing the 000-default.conf file with the virtual host for the regular domain and the one for nextcloud snap, apache2 won’t restart: running systemctl restart apache2, I get an error message:
    “Job for apache2.service failed because the control process exited with error code.
    See “systemctl status apache2.service” and “journalctl -xe” for details.”
    I don’t nknow what to do now. I checked again all the 000-default.conf file but without finding any mistake. If you’d had an idea, it would be much appreciated. Thanks in advance!

    Reply
  2. Hi Roman,
    It took me three weeks, from never had set-up a server to have a Lychee and Next cloud running in parallel. Both with an SSL certificate.
    I would not have been able to do that if it had not been for countless hours I spent both on your channel and on this website,
    Thank you!
    I will make sure to check out your merchandise, or patreon if you have one.

    Danke, Merci!

    Reply
  3. Hello Roman,
    Thanks a lot for the effort you made with your channel and with your youtube channel. It has been a very good source for me. Still I have got an issue with my install and I can not find the solution. Maybe you can help.

    Ubuntu: 20.01 LTS
    Nexcloud install with snap

    Followed commands:
    $ sudo snap install nextcloud
    $ sudo nextcloud.manual-install admin ###password###
    $ sudo snap set nextcloud ports.http=81
    $ sudo nextcloud.occ config:system:set trusted_domains 0 –value=https://cloud.mydomain.com
    $ sudo snap connect nextcloud:removable-media
    $ sudo nano /var/snap/nextcloud/current/nextcloud/config/config.php
    –> I changed the data directory to the one that I use

    $ sudo nano /etc/apache2/sites-available/000-default.conf
    –> Here I pasted your code sniplet. Here I display my complete 000-default.conf (because I think the problem probably here). Ps: I am also running a jellyfin service @ jellyfin.mydomain.nl (that on works). On my host server I made 2 CNAME entries: 1= cloud@mydomain.nl and 2=jellyfin@mydomain.nl

    ServerName mydomain.nl
    ServerAdmin webmaster@mydomain.nl
    DocumentRoot /var/www/html
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    ServerName jellyfin.mydomain.nl

    # Uncomment for HTTP to HTTPS redirect
    # Redirect permanent / https://DOMAIN_NAME

    ErrorLog /var/log/apache2/DOMAIN_NAME-error.log
    CustomLog /var/log/apache2/DOMAIN_NAME-access.log combined

    # If you are not using a SSL certificate, replace the ‘redirect’
    # line above with all lines below starting with ‘Proxy’

    ServerName jellyfin.mydomain.nl
    # This folder exists just for certbot(You may have to create it, chown and chm>
    DocumentRoot /var/www/html/jellyfin/public_html

    ProxyPreserveHost On

    # Letsencrypt’s certbot will place a file in this folder when updating/verifyi>
    # This line will tell apache to not to use the proxy for this folder.
    ProxyPass /.well_known/ !

    ProxyPass “/socket” “ws://127.0.0.1:8096/socket”
    ProxyPassReverse “/socket” “ws://127.0.0.1:8096/socket”

    ProxyPass “/” “http://127.0.0.1:8096/”
    ProxyPassReverse “/” “http://127.0.0.1:8096/”

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/mydomain.nl/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/mydomain.nl/privkey.pem
    Protocols h2 http/1.1

    # Enable only strong encryption ciphers and prefer versions with Forward Secre>
    SSLCipherSuite HIGH:RC4-SHA:AES128-SHA:!aNULL:!MD5
    SSLHonorCipherOrder on

    # Disable insecure SSL and TLS versions
    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1

    ErrorLog /var/log/apache2/jellyfin.mydomain.nl-error.log
    CustomLog /var/log/apache2/jellyfin.mydomain.nl-access.log combined

    # nextcloud

    ServerName cloud.mydomain.nl
    ServerAdmin webmaster@mydomain.nl
    ProxyPreserveHost On
    ProxyRequests Off
    RewriteEngine On
    RewriteRule ^/\.well-known/carddav http://%{SERVER_NAME}/remote.php/dav/ [>
    RewriteRule ^/\.well-known/caldav http://%{SERVER_NAME}/remote.php/dav/ [R>
    RewriteRule ^/\.well-known/host-meta http://%{SERVER_NAME}/public.php?serv>
    RewriteRule ^/\.well-known/host-meta\.json http://%{SERVER_NAME}/public.ph>
    RewriteRule ^/\.well-known/webfinger http://%{SERVER_NAME}/public.php?serv>
    ProxyPass / http://localhost:81/
    ProxyPassReverse / http://localhost:81/

    # vim: syntax=apache ts=4 sw=4 sts=4 sr noet

    ======================
    I really hope you can help me becaus it drives me crazy!
    Thanks a lot!

    Reply
    • hope you found a solution since then! I’m also kind of getting crazy right now 🙂 In my case, the server refused to start because of an error. I could debug with “sudo apachectl configtest” which allowed me to find out that apache modules were missing in my installation. Furthermore, I think it is goot to leave the original virtual host block in 000-default.conf. Maybe it helps to sort out cases where no domain name is given in the header of the request to the server (?)

      Reply
  4. Hello!
    First of all: great job with these tutorials! Thank you!

    I’m installing my own server at home and I’m learning a lot of stuff; your videos and tutorials are awesome.

    May you explain a little why do you need the “RewriteRule” statements with Nextcloud??

    Thank you again!

    Reply
    • Glad you like them!
      The first two rewrite rules are required if you want to access your calendar or contacts using a different client (mail, android sync). The others are needed to avoid getting some error messages in Nextcloud but frankly I forgot what exactly they are needed for. Not that you don’t need them, Nextcloud works just fine without any rewrite rules but not all features will work correctly.

      Reply

Leave a Comment

Dear reader

Ads allow me to dedicate a significant amount of time into the creation of valuable content both on YouTube as well as on this website.

Please support my work by disabling your ad blocker or whitelisting this site!

Alternatively, you can remove all ads on this site by becoming a supporter for as little as 2$/month. Thereby, you will directly support my content on YouTube and on this blog!