Netlify replacement to deploy simple websites with better flexibility, speed and without vendor lock-in
MIT License
Deploy simple websites with Google Cloud and Cloudflare. It is like Netlify with:
You will have built-in HTTPS and deploy by git push
.
We also have trade-offs. It is not free, but for a simple website, it will cost you cents per month. You need more steps to install it, but after you have the same simple workflow.
Create an account in Google Cloud.
Go to IAM & Admin → Service Accounts, click Create Service Account and fill form:
Github-actions
Deploy from Github Actions
Add Cloud Run Admin, Storage Admin, Service Account User roles.
Click Create Key, choose JSON → Create, download and keep file for a while.
Open Container Registry and enable the service.
Open Cloud Run and start the service.
Go to your Github page of your project at Settings → Secrets.
Add new secret WEBSITE_URL
with URL to your website domain
(like example.com
).
Add new secret GCLOUD_PROJECT
with Google Cloud project name like
test-255417
. You can find project ID by opening a project switcher
at the top of Google Cloud.
Choose application name (like examplecom
) and add GCLOUD_APP
secret with
this name.
Call base64 key-partition-….json
(file from step 4) and add GCLOUD_AUTH
secret with the base64 content of this file.
Install Solid State Deploy to your project.
npm i ssdeploy
Create Github Actions workflow by calling:
npx ssdeploy init
Your project should build HTML files by npm build
and put them to dist/
.
Push the project’s changes to Github Actions to start deploying. Open Actions tab on Github to check out the process.
Go to Cloud Run at Google Cloud and find your server. Open it
by clicking on the name and find the URL like examplecom-hjv54hv.a.run.app
.
Check that the website is working.
Click on Manage Custom Domains → Add mapping. Select your app, Verify a new domain, and enter your domain name. Finish domain verification with Webmaster Central.
After verification open Add mapping dialog again, select your app,
domain, and leave subdomain blank. You will get A
and AAAA
records.
Create a new Cloudflare account.
Create a site with A
and AAAA
records from Cloud Run.
Enable HTTP/3 and 0-RTT in Cloudflare Network settings.
Find Zone ID at site overview and create API token
with cache cleaner
name and Cache Purge
/Edit
permission.
Use them in CLOUDFLARE_ZONE
and CLOUDFLARE_TOKEN
secrets at Github.
Go to Google Cloud Run, Manage Custom Domains → Add mapping
to add www
subdomain and add CNAME
record to Cloudflare DNS
settings.
We recommend checking the final result for blocking in Russia and recreate Cloudflare account to change IP addressed.
Few extra steps will improve security:
Go to Cloudflare SSL/TLS settings and enable Full encryption mode.
Add CAA
records to Cloudflare DNS settings:
CAA @ 0 "only allow specific hostname" digicert.com
CAA @ 0 "only allow specific hostname" letsencrypt.org
CAA www 0 "only allow specific hostname" digicert.com
CAA www 0 "only allow specific hostname" letsencrypt.org
Enable DNSSEC in DNS settings.
Enable HTST by creating nginx.conf
in the root of your project with:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header X-Content-Type-Options "nosniff";
Just push commits to master
:
git push origin master
You can switch deploy branch at .Github/workflows/deploy.yml
.
To test the Docker image locally run:
npm build
npx ssdeploy run
You can deploy a server from the laptop. It can be useful to debug.
You need to install Google Cloud SDK and call:
npx ssdeploy deploy
In custom Nginx config, you can define headers and redirects. Create nginx.conf
in your project root.
if ($host ~ ^www\.(?<domain>.+)$) {
return 301 https://$domain$request_uri;
}
location ~* "(\.css|\.png|\.svg|\.woff2)$" {
add_header Cache-Control "public, max-age=31536000, immutable";
}
It will be included inside the server
context.
Custom Dockerfile
should be placed at your project root. It can be used
to define crontab jobs:
FROM nginx:alpine
RUN rm -R /etc/nginx/conf.d
COPY ./dist/ /var/www/
COPY ./node_modules/ssdeploy/configs/nginx.conf /etc/nginx/nginx.template
COPY ./nginx.conf /etc/nginx/server.conf
RUN echo "#\!/bin/sh\necho 1" > /etc/periodic/hourly/example
RUN chmod a+x /etc/periodic/hourly/example
CMD crond && envsubst \$PORT < /etc/nginx/nginx.template > /etc/nginx/nginx.conf && nginx