Skip to content

Instantly share code, notes, and snippets.

@deven-sitapara
Last active December 5, 2024 15:43
Show Gist options
  • Save deven-sitapara/602f6f4652d79b879827727ac49c2e3f to your computer and use it in GitHub Desktop.
Save deven-sitapara/602f6f4652d79b879827727ac49c2e3f to your computer and use it in GitHub Desktop.
Setup VPS

VPS Server Setup

Setup react app, python api and mysql database.

Update server


sudo apt-get update

User creation


  1. Create a New Non-Root User:

    adduser deployuser
    usermod -aG sudo deployuser
    • This limits root-level access, reducing risks from accidental or malicious changes.
  2. Disable Root Login via SSH:

    • Edit /etc/ssh/sshd_config:

      PermitRootLogin no
    • Restart SSH:

      systemctl restart ssh
  3. Use SSH Keys for Authentication:

    • Generate SSH keys locally:

      ssh-keygen -t rsa -b 4096
    • Copy the public key to the server:

      ssh-copy-id deployuser@your_server_ip
    • Disable password login in /etc/ssh/sshd_config:

      ~~PasswordAuthentication no~~
      #open ssh port 
      sudo ufw allow 22
      sudo ufw allow 443
      sudo ufw allow 80
    💡

    to remove port allow

    sudo ufw delete allow 8089
    💡

    Note: For now don’t disable password authentication

Python Setup

Python 3.10.15

sudo apt-get install python3 python3-dev python3-pip 
💡

To clear pip cache

pip cache purge

Clone Python Repo

git clone repo@github.git
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Install & Setup Gunicorn for web server

pip install gunicorn
sudo apt install supervisor
sudo nano /etc/supervisor/conf.d/django.conf
[program:gunicorn]
command=/home/deployuser/api.domain.com/.env/bin/gunicorn core.wsgi:application \
    --workers 4 \  # Number of worker processes
    --threads 4 \  # Number of threads per worker
    --bind 127.0.0.1:8000 \
    --timeout 120  # Adjust timeout for long-running requests
directory=/home/deployuser/api.domain.com
user=deployuser
autostart=true
autorestart=true
stdout_logfile=/var/log/gunicorn.log
stderr_logfile=/var/log/gunicorn_err.log
sudo apt install supervisor
sudo supervisorctl reread
sudo supervisorctl update
sudo systemctl restart supervisor

sudo supervisorctl stop gunicorn

Check if any error

sudo tail -f  /var/log/gunicorn.log
sudo tail -f  /var/log/gunicorn_err.log

Setup Nginx

https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04

API in Nginx

sudo apt install nginx
sudo nano /etc/nginx/sites-available/api.domain.com
server {
    server_name new-api.domain.com;

    error_log /home/deployuser/nginx_error.log;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/new-api.domain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/new-api.domain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = new-api.domain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name new-api.domain.com;
    return 404; # managed by Certbot
}

React App in Nginx

sudo nano /etc/nginx/sites-available/erp.domain.com
server {
    listen 80;
    server_name new-erp.domain.com;

    root /var/www/erp.domain.com/dist;
    index index.html;

    location / {
        # try_files $uri $uri/ /index.html;
         try_files $uri /index.html;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
			# add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self';";
    }

    error_page 404 /index.html;

    location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|map|mp4)$ {
       expires 6M;
        access_log off;
         add_header Cache-Control "public";
    }

}
sudo ln -s /etc/nginx/sites-available/erp.domain.com /etc/nginx/sites-enabled
sudo ln -s /etc/nginx/sites-available/api.domain.com /etc/nginx/sites-enabled
sudo chown -R www-data:www-data /home/deployuser/api.domain.com
sudo chmod -R 755 /home/deployuser/api.domain.com

cd /home/deployuser/erp.domain.com/ && npm i
sudo /home/deployuser/erp.domain.com/node_modules/vite/bin/vite.js build
sudo chown -R www-data:www-data /home/deployuser/erp.domain.com
sudo chmod -R 755 /home/deployuser/erp.domain.com
sudo systemctl restart nginx
sudo systemctl enable nginx
sudo systemctl reload nginx

Check log if any error

sudo tail -f /var/log/nginx/error.log

SSL install

Certbot install auto add to config file

https://www.linkedin.com/pulse/how-install-lets-encrypt-free-ssl-certbot-ubuntu-renew-bhuskute-zxicf/

 sudo apt update && sudo apt upgrade -y
 sudo apt install --reinstall python3-pip python3-venv python3-setuptools python3-certbot python3-cffi
 sudo apt install python3-dev libffi-dev libssl-dev build-essential -y
 sudo apt remove --purge certbot python3-certbot -y
 sudo snap install --classic certbot
 sudo ln -s /snap/bin/certbot /usr/bin/certbot
 sudo certbot --nginx
 
Certificate is saved at: /etc/letsencrypt/live/new-api.domain.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/new-api.domain.com/privkey.pem
Certificate is saved at: /etc/letsencrypt/live/new-erp.domain.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/new-erp.domain.com/privkey.pem

Security

sudo apt install fail2ban
sudo ufw enable
sudo apt install unattended-upgrades

DB Server Setup

Setup Server like above → here

Open Ports

https://www.cyberciti.biz/faq/how-to-delete-a-ufw-firewall-rule-on-ubuntu-debian-linux/

sudo ufw allow 22
sudo ufw allow 3306
sudo apt update
sudo apt install mysql-server
sudo apt install mysql-client
sudo service mysql start
sudo mysql_secure_installation
sudo mysql -u root -p
CREATE USER 'lg_user'@'ip' IDENTIFIED BY 'newpass';
 
 

Bind MySQL to All IPs

By default, MySQL binds only to 127.0.0.1 (localhost). To allow remote connections, you need to change the bind address to 0.0.0.0

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 0.0.0.0

This allows MySQL to listen for connections on all IP addresses. Save the file and exit the editor.


sudo apt install mysqltuner
sudo mysqltuner

update .my.cnf file

nano ~/.my.cnf

Testing : locust to run api testing

locust -f locustfile.py

Reference

Setup VPS

https://github.com/dreamsofcode-io/zenstats/blob/main/docs/vps-setup.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment