map $sent_http_content_type $expires {
"text/html" epoch;
"text/html; charset=utf-8" epoch;
default off;
}
server {
listen 80;
listen 443 ssl http2;
server_name example.com;
if ( $scheme = "http" ) {
return 301 https://$host$request_uri;
}
# SSL
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# security headers
# add_header X-Robots-Tag "noindex, nofollow";
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
#add_header Content-Security-Policy "default-src 'self' http: https: ws: wss: data: blob: 'unsafe-inline'; frame-ancestors 'self';" always;
add_header Permissions-Policy "interest-cohort=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location /api/ {
expires off;
proxy_pass http://127.0.0.1:3000/api/;
proxy_cache off;
}
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header "Connection" "";
# Proxy timeout
proxy_send_timeout 1m;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
location / {
expires $expires;
proxy_pass http://127.0.0.1:3000/;
}
access_log off;
error_log /var/log/nginx/example.com-error.log error;
# ACME-challenge
location ^~ /.well-known/acme-challenge/ {
root /var/www/_letsencrypt;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
Last active
February 2, 2024 17:10
-
-
Save eliyas5044/c137329e800ef4761d8209dd356b5410 to your computer and use it in GitHub Desktop.
Github action to deploy Nuxt.js project into Cloud server.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Deploy to aws | |
name: Deploy to AWS | |
# Controls when the action will run. | |
on: | |
push: | |
branches: [main] | |
# A workflow run is made up of one or more jobs that can run sequentially or in parallel | |
jobs: | |
build: | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest] | |
node: [14] | |
# Steps represent a sequence of tasks that will be executed as part of the job | |
steps: | |
- name: Checkout 🛎 | |
uses: actions/checkout@master | |
- name: Setup node env 🏗 | |
uses: actions/[email protected] | |
with: | |
node-version: ${{ matrix.node }} | |
check-latest: true | |
- name: Get yarn cache directory path 🛠 | |
id: yarn-cache-dir-path | |
run: echo "::set-output name=dir::$(yarn cache dir)" | |
- name: Cache node_modules 📦 | |
uses: actions/[email protected] | |
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) | |
with: | |
path: ${{ steps.yarn-cache-dir-path.outputs.dir }} | |
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} | |
restore-keys: | | |
${{ runner.os }}-yarn- | |
- name: Install dependencies 👨🏻💻 | |
run: yarn install --prefer-offline --frozen-lockfile --non-interactive --production=false | |
- name: Make envfile | |
uses: SpicyPizza/[email protected] | |
with: | |
envkey_APP_NAME: ${{ secrets.APP_NAME }} | |
envkey_APP_SHORT_NAME: ${{ secrets.APP_SHORT_NAME }} | |
envkey_APP_URL: ${{ secrets.APP_URL }} | |
envkey_API_BASE_URL: ${{ secrets.API_BASE_URL }} | |
envkey_AWS_CDN: ${{ secrets.AWS_CDN }} | |
envkey_GOOGLE_MAP_KEY: ${{ secrets.GOOGLE_MAP_KEY }} | |
- name: Run builder | |
run: yarn build | |
- name: Install production dependencies | |
run: | | |
rm -rf node_modules | |
NODE_ENV=production yarn install --prefer-offline --pure-lockfile --non-interactive --production=true | |
- name: Archive necessary folders and files | |
uses: montudor/action-zip@v1 | |
with: | |
args: zip -qq -r dist.zip .env .nuxt static nuxt.config.js node_modules package.json ecosystem.config.js | |
# Configure AWS credential and region environment variables for use with the AWS CLI and AWS SDKs | |
- name: Configure AWS credentials | |
uses: aws-actions/configure-aws-credentials@v1 | |
with: | |
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
aws-region: ${{ secrets.AWS_REGION }} | |
- name: Upload to Amazon S3 | |
run: aws s3 sync --delete .nuxt/dist/client s3://${{ secrets.AWS_S3_DESTINATION }} | |
- name: Install SSH key | |
uses: shimataro/ssh-key-action@v2 | |
with: | |
key: ${{ secrets.SSH_KEY }} | |
known_hosts: ${{ secrets.HOST }} | |
- name: Adding Known Hosts | |
run: ssh-keyscan -H ${{ secrets.HOST }} >> ~/.ssh/known_hosts | |
- name: Rsync over ssh | |
run: rsync -avz dist.zip ${{ secrets.USERNAME }}@${{ secrets.DEMO_HOST }}:/home/${{ secrets.USERNAME }} | |
- name: Executing remote ssh commands using ssh key | |
uses: appleboy/ssh-action@master | |
env: | |
SHA: ${{ github.sha }} | |
USERNAME: ${{ secrets.USERNAME }} | |
APP_NAME: ${{ secrets.APP_SHORT_NAME }} | |
with: | |
host: ${{ secrets.HOST }} | |
username: ${{ secrets.USERNAME }} | |
key: ${{ secrets.SSH_KEY }} | |
envs: USERNAME,APP_NAME | |
script: | | |
export PATH=/home/ubuntu/.fnm:$PATH | |
eval "`fnm env`" | |
source ~/.bashrc | |
rm -rf app | |
mkdir app | |
mv dist.zip app | |
cd app | |
unzip dist.zip | |
pm2 delete DemoApp | |
pm2 start --only DemoApp |
- We need to add these as key, value pair in Github Secrets
APP_NAME="My Demo App"
APP_SHORT_NAME="MyDemoApp"
APP_URL=https://my-demo-app.com
API_BASE_URL=https://api.my-demo-app.com
AWS_CDN=https://cdn.my-demo-app.com
GOOGLE_MAP_KEY=some_random_string
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
AWS_S3_DESTINATION="bucket/folder"
# SSH private key
SSH_KEY=
# Server host address
HOST=
# Server username
USERNAME=
- SSH into server
- Update server dependencies
- Generate RSA ssh key
- Apped public key into
authorized_keys
- Add private key into github secrets
- Install
unzip
package
sudo apt install unzip
- Install fnm node manager
curl -fsSL https://fnm.vercel.app/install | bash
source /home/ubuntu/.bashrc
- Install pm2
npm install -g pm2
- Init System pm2 Service
pm2 startup
To setup the Startup Script, copy/paste the following command 9. Install nginx
sudo apt install nginx
- Configure nginx config file
cd /etc/nginx/sites-available
sudo nano my-demo-app.com.conf
- Paste the bellow config file as example
map $sent_http_content_type $expires {
"text/html" epoch;
"text/html; charset=utf-8" epoch;
default off;
}
server {
listen 80; # the port nginx is listening on
server_name my-demo-app.com; # setup your domain here
gzip on;
gzip_types text/plain application/xml text/css application/javascript;
gzip_min_length 1000;
location / {
expires $expires;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
proxy_pass http://127.0.0.1:3000;
}
}
- Save the file with
Command + O
orCtrl + O
and exit by pressingX
keyboard - Create symbolic link into nginx
sites-enabled
folder
sudo ln -s /etc/nginx/sites-available/my-demo-app.com.conf /etc/nginx/sites-enabled/
- Check the nginx by
sudo nginx -t
- If nginx config is OK, then reload nginx by
sudo service nginx reload
- Install Let's Encrypt to add SSL certificate
cd ~
sudo apt update
sudo apt install certbot python3-certbot-nginx
- Get SSL certificate
sudo certbot --nginx -d my-demo-app.com
or
sudo certbot certonly --standalone --preferred-challenges http -d my-demo-app.com
- Verifying Certbot Auto-Renewal
sudo systemctl status certbot.timer
sudo certbot renew --dry-run
- SSH into server
ssh user@host
// or
ssh -i ~/.ssh/ubuntu.pem ubuntu@server_ip_address
- Update server dependencies
sudo apt update
sudo apt upgrade -y
- Generate RSA ssh key
ssh-keygen -t rsa -b 4096 -C "[email protected]"
- This creates a new SSH key, using the provided email as a label.
- When you're prompted to "Enter a file in which to save the key," press Enter. This accepts the default file location.
- You’ll also be asked to provide a passphrase. Leave this empty by pressing Enter since we can’t enter passwords when Github Actions run the SSH command for us.
We need to add the public key (id_rsa.pub
) to authorized_keys
so machines using the private key (id_rsa
) can access the server.
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
- Go to your repository on Github and click on Settings, then Secrets, then Actions. You should see a button that says New repository secret.
- Write Name, here we'll use
SSH_KEY
- Write Value, to get value, we need to go back to server and copy private key.
cat ~/.ssh/id_rsa
- Copy the whole key starting from -----BEGIN OPENSSH PRIVATE KEY----- and ending at -----END OPENSSH PRIVATE KEY----- and paste in Value and click Add secret button.
- Add
HOST
secret in Github, here HOST=IP_ADDRESS_OF_HOST
- name: Install SSH key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.SSH_KEY }}
known_hosts: ${{ secrets.HOST }}
- We can generate correct
know_hosts
usingssh-keyscan
command likessh-keyscan -H IP_ADDRESS_OF_HOST
- Let's add this in Github action
- name: Adding Known Hosts
run: ssh-keyscan -H ${{ secrets.HOST }} >> ~/.ssh/known_hosts
We can finally rsync via SSH into the server. Github action is like this - here HOST = Server IP address and USERNAME = Server username
- name: Rsync over ssh
run: rsync -avz dist.zip ${{ secrets.USERNAME }}@${{ secrets.HOST }}:/home/${{ secrets.USERNAME }}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment