Selfserved Ghost + Webflow integration with Caddy
3 min read

Modern SaaS applications usually run a landing page, blog, and 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</your_domain>* instead of a subdomain *blog.<your_domain>.com</your_domain>* for SEO purposes. You want as many links to your main domain as possible. The more content on *<your_domain>.com/blog</your_domain>*, the more Google will index it.
Running Ghost blog on a subdomain such as *blog.<your_domain>.com</your_domain>* 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</your_domain>* on a Webflow and *<your_domain>.com/blog</your_domain>* being self-hosted Ghost you need a [reverse-proxy](https://en.wikipedia.org/wiki/Reverse_proxy) server.
<ImageBlock src="https://adapty.io/wp-content/uploads/2023/01/602057636a5d4c530ec414e7_uuksuwzn_7uwyip5fzuiw-p56qcivgumdmrpqcv6-cjcqfcumr6cw2einfygrznvix3u9wpzbtmpvdimajhd4f2fui_dwavuholitwafukoptuo_otvrr_5xdu-k1yavy4mzt3nh.png" alt="" caption="Reverse proxy server" />
## Adjusting Caddy for reverse proxy
From a devops point of view our goals are:
1. *<your_domain>.com</your_domain>* -> Webflow
2. *<your_domain>.com/*</your_domain>* -> Webflow
3. *<your_domain>.com/blog</your_domain>* -> self hosted Ghost blog
4. *blog.<your_domain>.com</your_domain>* -> *<your_domain>.com/blog</your_domain>*
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.
<CodeBlock language="yaml" code="version: "3.7"nservices: 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/contentnvolumes: caddy_data: caddy_config:" />
Now for *Caddyfile*:
<CodeBlock language="nginx" code="blog.adapty.io {ntredir https://adapty.io/blog{uri}n}nadapty.io {ntredir /blog /blog/ntreverse_proxy /blog/* ghost:2368 {ntt#proxy to Ghost containernttheader_up Host {host}nt}ntreverse_proxy proxy.webflow.com {ntt#proxy to Webflownttheader_up Host {host}nt}n}" />
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).
Lastly,
Point A record for the main domain to your IP.
<ImageBlock src="https://adapty.io/wp-content/uploads/2023/01/6020576367e8b989331cfc49_evpqege4ulcknkhvhh98tdjcduudww_edg5jdqklk7dbk3twnefqoiypyabyfbm4lgy8iyivmiyf99jfdp89honxdz8gq5wfdl-2oamvwjp0imlcfksdtbqdnpflt4uk3s0n2lyy.png" alt="A record in DNS" caption="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).
<ImageBlock src="https://adapty.io/wp-content/uploads/2023/01/6020576235ee5c2428c6965b_-ebe7pobpzxmz0ouzd8x7lofu0xv9vx-riqiiclykea4idgqk28u3gvb9eauwioiw2lqjahkqshpaxu9nepom-q8zlvxdn9-a9j5odcnmh1_u8c9r4izkrfifihmsb9c9ee_sj4.png" alt="advanced publishing options" caption="Turn off SSL in Webflow as Caddy will create a certificate for you" />
That’s it!




