Skip to content

Instantly share code, notes, and snippets.

@adriansteffan
Last active January 6, 2024 16:06
Show Gist options
  • Save adriansteffan/48c9bda7237a8a7fcc5bb6987c8e1790 to your computer and use it in GitHub Desktop.
Save adriansteffan/48c9bda7237a8a7fcc5bb6987c8e1790 to your computer and use it in GitHub Desktop.
A description of how to map a specific domain to a webservice running inside a docker container. Used as personal documentation.

Apache Config: map domain to docker container

The goal: Make the webservice hosted inside a docker container available through a specific domain that we own (let's say mycooldomain.com - keep in mind to replace this placeholder name with your actual domain in EVERY instance).

For this to work on a standard linux distro, apache and certbot need to be installed. Additionally, a need a specific set of apache modules need to be enabled for this to work.

sudo apt install apache2 certbot python3-certbot-apache
a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel 
a2enmod headers
a2enmod rewrite
a2enmod ssl

Starting Point

Let's assume that our docker-compose looks something like this:

version: "3"
services:
    webservice:
        build: .
        ports: 
            - "127.0.0.1:XXXX:80"

with XXXX being an arbitrary internal port that our docker container binds to.

When in doubt, use

netstat -tln

to see what ports are already in use.

Apache Config

To start off, create a file named mycooldomain.com.conf in /etc/apache2/sites-available with the following content (replacing mycooldomain.com with your domain and XXXX with the port used by your docker container)

Default (application does not need websockets)

<VirtualHost *:80>
        ServerName mycooldomain.com

        # Redirect http requests to https
        RewriteEngine On
        RewriteCond %{SERVER_NAME} =mycooldomain.com
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<IfModule mod_ssl.c>
        <VirtualHost *:443>
                ServerName mycooldomain.com

                # Forward host header
                ProxyPreserveHost On
                ProxyRequests Off

                # Proxy everything to backend
                ProxyPass / http://127.0.0.1:XXXX/
                ProxyPassReverse / http://127.0.0.1:XXXX/

                # SSL config
        </VirtualHost>
</IfModule>

<IfModule mod_mime.c>
   # Manifest file
   AddType application/manifest+json webmanifest
</IfModule>

Websockets with custom endpoint

<VirtualHost *:80>
        ServerName mycooldomain.com

        # Redirect http requests to https
        RewriteEngine On
        RewriteCond %{SERVER_NAME} =mycooldomain.com
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<IfModule mod_ssl.c>
        <VirtualHost *:443>
                ServerName mycooldomain.com
                
                ProxyPass /WEBSOCKET_ENDPOINT_OF_APP_HERE ws://127.0.0.1:XXXX/WEBSOCKET_ENDPOINT_OF_APP_HERE
                ProxyPassReverse /WEBSOCKET_ENDPOINT_OF_APP_HERE ws://127.0.0.1:XXXX/WEBSOCKET_ENDPOINT_OF_APP_HERE

                # Forward host header
                ProxyPreserveHost On
                ProxyRequests Off

                # Proxy everything to backend
                ProxyPass / http://127.0.0.1:XXXX/
                ProxyPassReverse / http://127.0.0.1:XXXX/

                # SSL config
        </VirtualHost>
</IfModule>

<IfModule mod_mime.c>
   # Manifest file
   AddType application/manifest+json webmanifest
</IfModule>

Websockets without custom endpoint

<VirtualHost *:80>
        ServerName mycooldomain.com

        # Redirect http requests to https
        RewriteEngine On
        RewriteCond %{SERVER_NAME} =mycooldomain.com
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<IfModule mod_ssl.c>
        <VirtualHost *:443>
                ServerName mycooldomain.com
                
                RewriteEngine On
                RewriteCond %{HTTP:Upgrade} websocket [NC]
                RewriteCond %{HTTP:Connection} upgrade [NC]
                RewriteRule .* "ws://127.0.0.1:XXXX%{REQUEST_URI}" [P]
        
                # Forward host header
                ProxyPreserveHost On
                ProxyRequests Off

                # Proxy everything to backend
                ProxyPass / http://127.0.0.1:XXXX/
                ProxyPassReverse / http://127.0.0.1:XXXX/

                # SSL config
        </VirtualHost>
</IfModule>

<IfModule mod_mime.c>
   # Manifest file
   AddType application/manifest+json webmanifest
</IfModule>

To enable your config, run

a2ensite mycooldomain.com.conf
systemctl reload apache2

to create a symlink in /etc/apache2/sites-enabled.

Set DNS Record

Next, head over to your domain registrar and set an A Record that points to the IP address of the host machine. If you are unsure how to do this, google "set A record YOUR-REGISTRAR-NAME".

SSL Certificate

In order to enable https for your domain, you can use certbot to create a ssl certificate.

Simply run

certbot

and enter the number next to mycooldomain.com. We do not need the http->https redirect, as our config already takes care of that.

After certbot finishes, thats it. Your webservide in the docker container is now reachable via mycooldomain.com.

Configuring automatic certificate renewal

Run

crontab -e

and choose your prefered editor (1 for nano).

At the botton, add

0 2 * * * certbot renew

This will check if your certificates need renewal every day at 2 am and renew them that if necessary.

To disable the daily emails telling you that no renewal was necessary, run:

certbot renew --quiet --post-hook "sudo service nginx reload"

Removing the config

In order to undo the actions described above, run the following commands:

a2dissite mycooldomain.com.conf
systemctl reload apache2
certbot delete --cert-name mycooldomain.com

and remove the file mycooldomain.com.conf from /etc/apache2/sites-available.

Adding Basic Auth to the Apache Config

To enable basic auth for a subdomain, add the following to the apache config (filling in your domain name):

<VirtualHost *:443>

       ...

        <Location />
                Deny from all
                AuthUserFile "/etc/apache2/passwd_files/mycooldomain.com.htpasswd"
                AuthName "Enter your credentials"
                AuthType Basic
                Satisfy Any
                require valid-user
        </Location>  
        
        ...
        
    </VirtualHost>

then, create the folder

mkdir -p /etc/apache2/passwd_files/

and create your credential file:

htpasswd -B -c /etc/apache2/passwd_files/mycooldomain.com.htpasswd root

and enter the password you want. (delete a user by deleting the line from the file)

Reload the apache once you are done.

@lochhh
Copy link

lochhh commented Nov 5, 2021

a2dissite auf die conf should be a2dissite mycooldomain.com.conf

@adriansteffan
Copy link
Author

a2dissite auf die conf should be a2dissite mycooldomain.com.conf

Thanks, that was an oversight from the drafting phase!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment