#docker #nginx #ecs #efs #page-speed
Idea
We had two options for our blogging
- Subscribe to ghost.org plan
- Host our own on aws
As we want to host our blog on a subdirectory https://finflux.co/blog, the first option was costly for us and hence we opted for the second option.
Our main website https://finflux.co is written in php + html5 + css and served using Nginx. So we finalised on following stack to cohost website and ghost using docker containers
- Nginx (pagespeed/nginx-pagespeed:latest)
- php-fpm (bitnami/php-fpm:latest)
- ghost (ghost:3-alpine)
- mysql as ghost backend
- Pagespeed - for faster web experience
To run locally
We modified Nginx server config to go to ghost blog On local, we want two things to happen. On http://localhost website should serve and on http://localhost/blog, the ghost blog should trigger. We did changes to docker-compose and .
docker-compose.yml
version: '2'
networks:
app-tier:
driver: bridge
services:
phpfpm:
image: 'bitnami/php-fpm:latest'
networks:
- app-tier
volumes:
- web-content:/app
nginx:
image: 'pagespeed/nginx-pagespeed:latest'
depends_on:
- phpfpm
- ghost
networks:
- app-tier
ports:
- '80:8080'
volumes:
- ./server.conf:/etc/nginx/conf.d/yourapp.conf
- ./website/:/app
ghost:
image: ghost:3-alpine
restart: always
networks:
- app-tier
ports:
- 8082:2368
environment:
# see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables
database__client: mysql
database__connection__host: host.docker.internal
database__connection__user: root
database__connection__password: xxxxxx
database__connection__database: ghost
url: http://localhost/blog
volumes:
web-content:
nginx server.conf
server {
listen 0.0.0.0:8080;
root /app;
error_page 404 /notfound.html;
location / {
# try_files $uri $uri/index.php;
index index.php;
}
location ~ \.php$ {
root /app;
fastcgi_pass phpfpm:9000;
fastcgi_index index.php;
# include the fastcgi_param setting
include fastcgi.conf;
}
pagespeed on;
pagespeed FileCachePath /var/cache/ngx_pagespeed;
# Ensure requests for pagespeed optimized resources go to the pagespeed handler
# and no extraneous headers get set.
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
add_header "" "";
}
location ~ "^/pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }
}
To run on Production
On production, we did following additional steps
- ECS to run docker containers
- ECR image of Finflux website
- Used SSM to store database password
- AWS logs for logging
- AWS efs(Elastic File Storage) - Ghost persistent storage
- SES as ghost email service
Dockerfile
FROM pagespeed/nginx-pagespeed:latest
LABEL maintainer="dev@finflux.co"
COPY ./website/ /app
COPY ./server.conf /etc/nginx/conf.d/yourapp.conf
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
docker-compose.yml
version: '3'
services:
phpfpm:
image: 'bitnami/php-fpm:latest'
volumes:
- web-content:/app
logging:
driver: awslogs
options:
awslogs-group: logging-group
awslogs-region: ap-south-1
awslogs-stream-prefix: website-phpfpm
nginx:
image: 'xyz.dkr.ecr.ap-south-1.amazonaws.com/finflux-website:${IMG_TAG}'
links:
- phpfpm
- ghost
depends_on:
- phpfpm
- ghost
ports:
- '80:8080'
volumes:
- web-content:/app
logging:
driver: awslogs
options:
awslogs-group: logging-group
awslogs-region: ap-south-1
awslogs-stream-prefix: website-nginx
ghost:
image: ghost:3-alpine
ports:
- 8080:2368
volumes:
- ghost-efs:/var/lib/ghost/content
environment:
# see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables
TZ: "${TIME_ZONE}"
database__client: mysql
database__connection__host: ${DB_HOST}
database__connection__user: ${DB_USER}
database__connection__database: ${DB_NAME}
mail__transport: SMTP
mail__options__port: 587
mail__options__host: ${SMTP_HOST}
mail__options__auth__user: ${SMTP_USER}
mail__options__auth__pass: ${SMTP_PASS}
mail__from: ${SMTP_EMAIL}
url: ${GHOST_URL}
logging:
driver: awslogs
options:
awslogs-group: logging-group
awslogs-region: ap-south-1
awslogs-stream-prefix: website-ghost
volumes:
web-content:
ghost-efs:
ecs-params.yml
version: 1
task_definition:
task_role_arn: "arn:aws:iam::xyz:role/ECS-TASK-EXECUTION-ROLE"
task_execution_role: "arn:aws:iam::xyz:role/ECS-TASK-EXECUTION-ROLE"
services:
ghost:
mem_reservation: 1024MB
secrets:
- value_from: "arn:aws:ssm:ap-south-1:xyz:parameter/website.dbpassword"
name: "database__connection__password"
nginx:
mem_reservation: 512MB
phpfpm:
mem_reservation: 256MB
efs_volumes:
- name: ghost-efs
filesystem_id: <efs-volumeId>
root_directory: /website