Webflow + Ghost blog with Caddy
Tags: docker, caddy, webflow, devops
Published: 2020-12-14 17:30:07

Modern SaaS applications usually run a landing page, blog, and the main app separately. For a landing page, you may want to use Tilda, Webflow, or other web-builders. For a blog, it’s common to use self-hosted CMS such as WordPress, Ghost, or others.

It’s crucially important to index the main domain *your_domain.com* instead of a subdomain *blog.your_domain.com* for SEO purposes. You want as many links to your main domain as possible. The more content on *your_domain.com/blog*, the more Google will index it.

Running Ghost blog on a subdomain such as *blog.your_domain.com* is easy, just create a new A-record in your DNS provider and point it to a machine with running Ghost instance. If you want to run *your_domain.com* on a Webflow and *your_domain.com/blog* being self-hosted Ghost you need a [reverse-proxy](https://en.wikipedia.org/wiki/Reverse_proxy) server.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vdfbeyms9kpk3vfyaj4x.png)
Reverse proxy server
From a devops point of view our goals are:

1. *your_domain.com* -> Webflow
2. *your_domain.com/** -> Webflow
3. *your_domain.com/blog* -> self hosted Ghost blog
4. *blog.your_domain.com* -> *your_domain.com/blog*

We’re going to use [Caddy](https://caddyserver.com/) for reverse-proxy. The reason is Docker-friendly config, super fast to deploy without deep knowledge of devops (hey, Nginx). Find the official Caddy image [here](https://hub.docker.com/_/caddy?tab=description). Caddy needs you to mount volumes for proper working.

We’ll host Ghost and Caddy on the same machine and in a single *docker-compose.yml* file.

    version: "3.7"
     
    services:
     caddy:
       image: caddy:2
       restart: unless-stopped
       ports:
         - "80:80"
         - "443:443"
       volumes:
         - $PWD/Caddyfile:/etc/caddy/Caddyfile
         - $PWD/site:/srv
         - caddy_data:/data
         - caddy_config:/config
     ghost:
       image: ghost:3
       environment:
         NODE_ENV: production
         url: https://adapty.io/blog
       volumes:
         - ./blog:/var/lib/ghost/content
    volumes:
     caddy_data:
     caddy_config:
    

Now for *Caddyfile*:

    blog.adapty.io {
       redir https://adapty.io/blog{uri} #point to subdirectory
    }
     
    adapty.io {
       redir /blog /blog/ #trailing slash
       reverse_proxy /blog/* ghost:2368 { #proxy to Ghost container
           header_up Host {host}
       }
       reverse_proxy proxy.webflow.com { #proxy to Webflow
           header_up Host {host}
       }
    }
    

Run *docker-compose up -d *and here you go!

By default, Caddy passes thru incoming headers to the backend—including the Host header—without modifications, with two exceptions:

- It adds or augments the X-Forwarded-For header field.
- It sets the X-Forwarded-Proto header field.

Read more in their docs [https://caddyserver.com/docs/caddyfile/directives/reverse_proxy#headers](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy#headers)

Lastly,

Point A record for the main domain to your IP.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/r9fjjtyasw7actmktha3.png)Change your DNS A record and point to a VM
In Webflow turn off SSL proxy as Caddy will serve it for you automatically (very cool, yeah? Without a certbot).
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h6tditcopnggf7vorig9.png)Turn off SSL in Webflow as Caddy will create a certificate for you
That’s it!