{"id":13473129,"url":"https://github.com/ai/ssdeploy","last_synced_at":"2025-04-06T16:10:49.707Z","repository":{"id":51933018,"uuid":"230968435","full_name":"ai/ssdeploy","owner":"ai","description":"Netlify replacement to deploy simple websites with better flexibility, speed and without vendor lock-in","archived":false,"fork":false,"pushed_at":"2024-07-18T14:19:46.000Z","size":541,"stargazers_count":194,"open_issues_count":0,"forks_count":6,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-11-24T17:54:36.547Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ai.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-30T19:25:18.000Z","updated_at":"2024-10-29T17:56:15.000Z","dependencies_parsed_at":"2024-01-14T08:49:26.595Z","dependency_job_id":"4cfd07b1-c0a3-407f-ab44-256c6cf4c819","html_url":"https://github.com/ai/ssdeploy","commit_stats":{"total_commits":230,"total_committers":2,"mean_commits":115.0,"dds":"0.021739130434782594","last_synced_commit":"9c7aa4ce57b70cf86be86b8a931285a34ad9b079"},"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai%2Fssdeploy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai%2Fssdeploy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai%2Fssdeploy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ai%2Fssdeploy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ai","download_url":"https://codeload.github.com/ai/ssdeploy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247509221,"owners_count":20950232,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T16:01:01.043Z","updated_at":"2025-04-06T16:10:49.679Z","avatar_url":"https://github.com/ai.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Solid State Deploy\n\nDeploy simple websites with Google Cloud and Cloudflare.\nIt is like Netlify with:\n\n* **Better performance.** Cloudflare has more features for fast websites\n  than Netlify CDN. For instance, HTTP/3 and TLS 1.3 0-RTT.\n* **Flexibility.** You can have crontab jobs and simple scripts\n  (without persistence storage). You will have powerful and well documented\n  Nginx config to define custom headers and redirects.\n* **Lack of vendor lock-in.** We use industry standards like Docker\n  and Nginx. You can change CI, CDN, or Docker cloud separately.\n* **Local tests.** You can run a server on your laptop to test redirects\n  and scripts.\n\nYou will have built-in HTTPS and deploy by `git push`.\n\n\u003cimg src=\"./example.png\" alt=\"ssdeploy example\" width=\"593\"\u003e\n\nWe also have trade-offs. It is not free, but for a simple website,\nit will cost you cents per month. You need more steps to install it,\nbut after you have the same simple workflow.\n\n\u003ca href=\"https://evilmartians.com/?utm_source=ssdeploy\"\u003e\n  \u003cimg src=\"https://evilmartians.com/badges/sponsored-by-evil-martians.svg\"\n       alt=\"Sponsored by Evil Martians\" width=\"236\" height=\"54\"\u003e\n\u003c/a\u003e\n\n## Install\n\n1. Create an account in [Google Cloud].\n2. Go to **IAM \u0026 Admin** → **Service Accounts**,\n   click **Create Service Account** and fill form:\n   * Service Account Name: `Github-actions`\n   * Service Account Description: `Deploy from Github Actions`\n3. Add **Cloud Run Admin**, **Storage Admin**, **Service Account User** roles.\n4. Click **Create Key**, choose **JSON** → **Create**, download and keep\n   file for a while.\n5. Open **Container Registry** and enable the service.\n6. Open **Cloud Run** and start the service.\n7. Go to your Github page of your project at **Settings** → **Secrets**.\n8. Add new secret `WEBSITE_URL` with URL to your website domain\n   (like `example.com`).\n9. Add new secret `GCLOUD_PROJECT` with Google Cloud project name like\n   `test-255417`. You can find project ID by opening a project switcher\n   at the top of [Google Cloud].\n10. Choose application name (like `examplecom`) and add `GCLOUD_APP` secret with\n   this name.\n11. Call `base64 key-partition-….json` (file from step 4) and add `GCLOUD_AUTH`\n    secret with the base64 content of this file.\n12. Install Solid State Deploy to your project.\n\n    ```sh\n    npm i ssdeploy\n    ```\n13. Create Github Actions workflow by calling:\n\n    ```sh\n    npx ssdeploy init\n    ```\n14. Your project should build HTML files by `npm build` and put them to `dist/`.\n15. Push the project’s changes to Github Actions to start deploying.\n    Open **Actions** tab on Github to check out the process.\n16. Go to **Cloud Run** at [Google Cloud] and find your server. Open it\n    by clicking on the name and find the URL like `examplecom-hjv54hv.a.run.app`.\n    Check that the website is working.\n17. Click on **Manage Custom Domains** → **Add mapping**. Select your app,\n    **Verify a new domain**, and enter your domain name.\n    Finish domain verification with Webmaster Central.\n18. After verification open **Add mapping** dialog again, select your app,\n    domain, and leave subdomain blank. You will get `A` and `AAAA` records.\n19. Create a new [Cloudflare] account.\n    Create a site with `A` and `AAAA` records from Cloud Run.\n20. Enable **HTTP/3** and **0-RTT** in Cloudflare **Network** settings.\n21. Find **Zone ID** at site overview and create **API token**\n    with `cache cleaner` name and `Cache Purge`/`Edit` permission.\n22. Use them in `CLOUDFLARE_ZONE` and `CLOUDFLARE_TOKEN` secrets at Github.\n23. Go to Google Cloud Run, **Manage Custom Domains** → **Add mapping**\n    to add `www` subdomain and add `CNAME` record to Cloudflare **DNS**\n    settings.\n\nWe recommend checking the final result\n[for blocking in Russia](https://isitblockedinrussia.com/) and recreate\nCloudflare account to change IP addressed.\n\nFew extra steps will improve security:\n\n1. Go to Cloudflare **SSL/TLS** settings and enable **Full** encryption mode.\n2. Add `CAA` records to Cloudflare **DNS** settings:\n\n   ```js\n   CAA @   0 \"only allow specific hostname\" digicert.com\n   CAA @   0 \"only allow specific hostname\" letsencrypt.org\n   CAA www 0 \"only allow specific hostname\" digicert.com\n   CAA www 0 \"only allow specific hostname\" letsencrypt.org\n   ```\n3. Enable **DNSSEC** in **DNS** settings.\n4. Enable **HTST** by creating `nginx.conf` in the root of your project with:\n\n   ```cpp\n   add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\";\n   add_header X-Content-Type-Options \"nosniff\";\n   ```\n\n[Google Cloud]: https://console.cloud.google.com/\n[Cloudflare]: https://www.cloudflare.com/\n\n\n## Deploy\n\nJust push commits to `master`:\n\n```sh\ngit push origin master\n```\n\nYou can switch deploy branch at `.Github/workflows/deploy.yml`.\n\n\n## Run Server Locally\n\nTo test the Docker image locally run:\n\n```sh\nnpm build\nnpx ssdeploy run\n```\n\n## Deploy Server Locally\n\nYou can deploy a server from the laptop. It can be useful to debug.\n\nYou need to install [Google Cloud SDK](https://cloud.google.com/sdk/install)\nand call:\n\n```sh\nnpx ssdeploy deploy\n```\n\n\n## Custom Nginx config\n\nIn custom Nginx config, you can define headers and redirects. Create `nginx.conf`\nin your project root.\n\n```cpp\nif ($host ~ ^www\\.(?\u003cdomain\u003e.+)$) {\n  return 301 https://$domain$request_uri;\n}\n\nlocation ~* \"(\\.css|\\.png|\\.svg|\\.woff2)$\" {\n  add_header Cache-Control \"public, max-age=31536000, immutable\";\n}\n```\n\nIt will be included inside the `server` context.\n\n\n## Custom Docker config\n\nCustom `Dockerfile` should be placed at your project root. It can be used\nto define crontab jobs:\n\n```sh\nFROM nginx:alpine\nRUN rm -R /etc/nginx/conf.d\nCOPY ./dist/ /var/www/\nCOPY ./node_modules/ssdeploy/configs/nginx.conf /etc/nginx/nginx.template\nCOPY ./nginx.conf /etc/nginx/server.conf\nRUN echo \"#\\!/bin/sh\\necho 1\" \u003e /etc/periodic/hourly/example\nRUN chmod a+x /etc/periodic/hourly/example\nCMD crond \u0026\u0026 envsubst \\$PORT \u003c /etc/nginx/nginx.template \u003e /etc/nginx/nginx.conf \u0026\u0026 nginx\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fai%2Fssdeploy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fai%2Fssdeploy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fai%2Fssdeploy/lists"}