In today's development world is easier than ever to deploy your projects online with minimal configuration, with frontend and JAM Stack/node powered apps there are a lot of good options: Vercel, Netlify, GitHub Pages, Gitlab Pages, Firebase Hosting.
Unfortunately for modern php/Laravel powered apps with Vue/React frontend there's no too many with minimal configuration with the quality of the options mentioned above out of Heroku before the change of its terms and I don't find a good one-to-one replacement for it.
Here I want to share my journey replicate a workflow close to the Heroku experience with less than 10 dollars/month.
The needs
I am talking about a semi-production ready app so what are our checklist
Separated
landing page
from the app. we don't want app errors affecting our marketing / guides pages neither slowing them down and want to implement SEO that probably our app itself doesn't need, because the routes are guarded.The
Main app
with Laravel/Jetstream and all resources we need for it (Database, cron tabs, redis)A
Database Manager
to quick review the database if we are far from our computer and we need to manage the data onlineOwnership, we don't need to pay extra money just to have a basic functionality we would like (now everything is a plugin, DB, Crons, etc...)
Build our frontend and deploy to the server when mergin our branch with master like Heroku and Vercel-like services do it.
For production app with > 100 paying customers maybe is better option to migrate to something like the Laravel services but for side projects maybe we just need to deploy and to show the app to your friends or get some users and see how it goes spending less as possible.
The solution (first attempt)
In my first attempt I used docker-compose to set up the environment with the services I needed here the most difficult part was serve the landing and app through Nginx as load balancer and its ssl but I found tools that make the task easier.
- Cloud provider: Digital Ocean
- Apps: Docker, Docker Compose
- Tools: ssl-companion, jwilder/nginx-proxy
Steps
On the server:
- Start a doplet with Digital Ocean (you have to give access to your ssh key when creating).
- Set up your domains in DO.
- Install docker
- Setup a git bare repository on your server to accept git push from your local as you push to Github (later I automized this step with a Laravel package insane/remotr and just need to set and set the
REMOTR_SERVER_IP
andREMOTR_REPO_NAME
in your.env
doc.).
On local:
- Verify that you can connect to your server via SSH
- Setup a docker-compose.yml for your Laravel project here was mine Loger's docker-compose.
- Add your server URL to git remote.
- git push
- Run your
docker compose up
command on the server via SSH and that's it
Maybe there's a shorter way to doit but not at USD 6.00 / Month without cold starts or using other services.
My current solution
Docker Compose with php and Laravel wasn't a good option for a $6 Doplet it was slower than my local environment out of the box so I ended up installing the LEMP stack.
One pain point I faced with the first approach was having to build the assets on my machine or the server it would be easier to manage this with GitHub actions so, I set it up.
Later I found a tutorial to connect Digital Ocean and GitHub actions I just needed the SSH key to push from GitHub Action instead of my local as the first approach. So, in every merge to master if the tests are green and after the archives of my frontend code is built a git push to the server is executed.
name: Laravel App Deployment
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
deploy:
if: ${{ github.event_name == 'push' }}
name: Deploy
runs-on: ubuntu-latest
needs: build
environment:
name: demo
url: ${{ secrets.SITE_URL }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install SSH Key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.DO_DOPLET_SECRET }}
known_hosts: unnecessary
- name: Adding Known Hosts
run: ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Download frontend build
uses: actions/download-artifact@v3
with:
name: frontend-build
path: public
- name: Store live name
run: git remote add live ${{ secrets.DO_REPO_URL }}
- name: Deploy with git
env:
branch_name: live_digital_ocean
run: |
echo "Deploy to staging server"
git config --global user.email "<>"
git config --global user.name "Action Bot"
git add .
git checkout -b $branch_name
git commit -m "deploy: build"
git push live $branch_name:master -f
echo "deployed to prod-staging"
- name: Update Composer PHP
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.DO_DOPLET_SECRET }}
script: |
cd /var/www/loger.com
composer update --ignore-platform-reqs
you can check the complete file here: https://github.com/jesusantguerrero/atmosphere/blob/master/.github/workflows/laravel.yml
Updated stack:
- IaaS: Digital Ocean Doplet
- Apps: NGINX, MariaDB, PHP 8.1
- Tools: cerbot, GitHub Actions
Steps
On the server:
- Start a Doplet with Digital Ocean (you have to give access to your SSH key when creating).
- Set up your domains in DO.
- Install docker
- Setup a git bare repository on your server to accept git push from your local as you push to GitHub (later I automized this step with a Laravel package insane/remotr and just need to set and set the
REMOTR_SERVER_IP
andREMOTR_REPO_NAME
in your.env
doc.).
On GitHub:
setup the SSH secrets that we need for the action:
SITE_URL
DO_REPO_URL
SSH_HOST
SSH_USER
DO_DOPLET_SECRET
Define our action Loger's deploy action
Honorable mentions:
- fly.io
- Digital Ocean App
Wrapping up
To summarize you can replicate the experience with a low cost using:
- Digital Ocean Doplet
- Create a git bare repository to push your changes with git
- Using Docker or LEMP Stack on the server
- Automate testing, build and deployment via SSH with GitHub actions
Thank you for reading, if you have any questions or want to share a stack the comments are open, as well as my Twitter and Github.
Top comments (0)