primatejs / primate

Web framework focused on flexibility and developer freedom
https://primatejs.com
MIT License
211 stars 9 forks source link

add `@primate/deploy` #126

Open terrablue opened 5 months ago

terrablue commented 5 months ago

Different providers

ralyodio commented 4 months ago

just a standalone server would be good too. no need to only support paid cloud offerings.

terrablue commented 4 months ago

@ralyodio how would such a deployment work?

ralyodio commented 4 months ago

Sync with a ssh

ralyodio commented 4 months ago

look at ./bin/deploy.sh and ./bin/post-deploy.sh in fastest-engineer-web -- that's how I deploy to a server.

There is some setup on the server that needs to happen first (nginx, systemd and directory paths)

ralyodio commented 4 months ago

// deploy.sh

#!/bin/bash

. $HOME/.bashrc
. .env
. .env.local

args=(-azvP --delete --exclude=node_modules --exclude=.idea --exclude=data --exclude=static/_posts)
hosts=($HOST_DOMAIN) # tornado lightning thunder tundra jefferson
dry=() #add --dry-run to enable testing
user=$HOST_USER
name=$HOST_PATH
project=$HOST_PROJECT

if [ -z "$name" ] || [ -z "$project" ]; then
    echo "One or both directories do not exist"
    exit 1
fi

result=$(ssh $user@$HOST_DOMAIN "[ -d ~/www/$name ] && [ -d ~/www/$name/$project ] && echo 'exists' || echo 'does not exist'")

if [ "$result" == "exists" ]; then
    # If both directories exist, run your command here
    echo "Both directories exist"

    for host in "${hosts[@]}"
    do
      echo ""
      date
      echo "---------------------"
      echo "syncing ${host}"
      echo "---------------------"
      rsync ${dry[@]} ${args[@]} ./ ${user}@${host}:www/${name}/${project}
      ssh -t ${user}@${host} \$HOME/www/${name}/${project}/bin/post-deploy.sh
    done

else
    echo "One or both directories do not exist"
fi

version=$(jq -r .version package.json)
say "$HOST_PROJECT is live!"
exit

//post-deploy.sh

#!/bin/bash

cd "$(dirname "$0")/.."
. $HOME/.bashrc
. .env
. .env.local

host=$HOST_DOMAIN
name=$HOST_PATH
project=$HOST_PROJECT

echo "current name: $name"

if [ -d "$HOME/www/${name}/${project}" ]; then
    # If both directories exist, run your command here
    echo "Both directories exist"
    cd $HOME/www/${name}/${project}
    nvm install v20
    node -v
    pnpm -v
    rm -f package-lock.json
    rm -f pnpm-lock.yaml
    rm -rf ./node_modules
        npm i -g pnpm
    #pnpm cache clean --force
    #pnpm cache verify
    pnpm i
        # curl --proto '=https' --tlsv1.2 -sSf https://install.surrealdb.com | sh -s -- --nightl
    sudo systemctl stop ${META_SERVICE}
    sudo systemctl stop surrealdb
    # surreal upgrade --nightly
    surreal upgrade
    sudo /etc/init.d/nginx reload
    sudo systemctl daemon-reload
    sudo systemctl start ${META_SERVICE}
    sudo systemctl start surrealdb
    # run migrations
    ./migrations/users.sh
    # ./migrations/comments.sh
    ./migrations/links.sh
    ./migrations/apikeys.sh
    ./migrations/products.sh
    # ./migrations/send_email.sh
    ./migrations/nostrusers.sh
    ./migrations/affiliates.sh
    ./migrations/appointments.sh
    ./migrations/payouts.sh
    ./migrations/waitlist.sh

  else
    echo "One or both directories do not exist"
fi
ralyodio commented 4 months ago

in my opinion if you gave us the ability to write our own deploy script and post deploy scripts (which runs on the server) that would be good enough for custom deploys.

terrablue commented 4 months ago

@ralyodio noted, I think that's the best way forward

ralyodio commented 4 months ago

maybe a ./bin/setup.sh too which would be ran once. I manually setup certs, symlink conf files and shit. I should script that.

ralyodio commented 4 months ago

Here's an example setup.sh script:

#!/bin/bash

. $HOME/.bashrc
. .env
. .env.local

# Check if the user provided the domain name and project name
if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: $0 <domain_name> <project_name>"
  exit 1
fi

# Variables
DOMAIN_NAME="$1"
PROJECT_NAME="$2"
TARGET_PATH="~/www/$DOMAIN_NAME/$PROJECT_NAME"
NGINX_CONF="$TARGET_PATH/etc/$DOMAIN_NAME.conf"
SYSTEMD_SERVICE="$TARGET_PATH/etc/$PROJECT_NAME.service"
NGINX_SYMLINK="/etc/nginx/sites-available/$DOMAIN_NAME.com.conf"
SYSTEMD_SYMLINK="/etc/systemd/system/$PROJECT_NAME.service"
user=$HOST_USER

# Create the directory if it does not exist
ssh $user@$HOST_DOMAIN "mkdir -p $TARGET_PATH"

# Deploy the code
rsync -azvP --delete --exclude=node_modules --exclude=.idea --exclude=data --exclude=static/_posts ./ ${user}@${HOST_DOMAIN}:${TARGET_PATH}

# Symlink the Nginx configuration
ssh $user@$HOST_DOMAIN "if [ -f $NGINX_CONF ]; then sudo ln -sf $NGINX_CONF $NGINX_SYMLINK && sudo ln -sf $NGINX_SYMLINK /etc/nginx/sites-enabled/; else echo 'Nginx configuration file not found at $NGINX_CONF'; exit 1; fi"

# Symlink the systemd service
ssh $user@$HOST_DOMAIN "if [ -f $SYSTEMD_SERVICE ]; then sudo ln -sf $SYSTEMD_SERVICE $SYSTEMD_SYMLINK; else echo 'Systemd service file not found at $SYSTEMD_SERVICE'; exit 1; fi"

# Generate Let's Encrypt certificates for the domain
ssh $user@$HOST_DOMAIN "sudo certbot certonly --nginx -d $DOMAIN_NAME"
ssh $user@$HOST_DOMAIN "sudo certbot certonly --nginx -d www.${DOMAIN_NAME}"

# Enable and start the systemd service
ssh $user@$HOST_DOMAIN "sudo systemctl enable $(basename $SYSTEMD_SERVICE) --now"

ssh -t ${user}@${HOST_DOMAIN} ${TARGET_PATH}/bin/post-deploy.sh

echo "Setup completed successfully!"

version=$(jq -r .version package.json)
say "$HOST_PROJECT is setup!"
exit
ralyodio commented 4 months ago

it could be smarter and write out .env.local based on questions you answer.

ralyodio commented 4 months ago

I also decided to support multiple environments. basically you just symlink .env.<envname> to .env.local and add those custom files to .gitignore

this makes it easiser for staging.example.com vs. example.com which a lot of clients want