Configuring Website Deployment on VDS/VPS
VDS/VPS is a virtual dedicated server with root access. It gives full environment control at an affordable price. Suitable for most commercial projects: Laravel, Django, Node.js, WordPress.
Initial Server Setup
# Connect
ssh root@YOUR_SERVER_IP
# Create deploy user (don't work as root)
useradd -m -s /bin/bash deploy
usermod -aG sudo deploy
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh && chmod 600 /home/deploy/.ssh/authorized_keys
# Disable root login via SSH
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd
# Basic packages
apt update && apt upgrade -y
apt install -y git curl wget nginx ufw fail2ban unzip
PHP + Laravel Stack
# PHP 8.3
add-apt-repository ppa:ondrej/php
apt install -y php8.3-fpm php8.3-cli php8.3-{pgsql,mysql,redis,xml,mbstring,curl,zip,gd}
# Composer
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
# Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
# PostgreSQL 16
apt install -y postgresql-16
sudo -u postgres createuser --superuser myapp_user
sudo -u postgres createdb myapp_prod -O myapp_user
Nginx Configuration for Laravel
# /etc/nginx/sites-available/myapp
server {
listen 80;
server_name example.com www.example.com;
root /var/www/myapp/current/public;
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
# Cache static files
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1024;
}
Let's Encrypt SSL
apt install -y certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com \
--non-interactive --agree-tos -m [email protected]
# Auto-renewal
systemctl enable --now certbot.timer
Deployment Structure (Deployer or Manual)
# /var/www/myapp/
# ├── current -> releases/20241115143022
# ├── releases/
# │ └── 20241115143022/
# ├── shared/
# │ ├── .env
# │ └── storage/
# deploy.sh
DEPLOY_PATH=/var/www/myapp
RELEASE=$DEPLOY_PATH/releases/$(date +%Y%m%d%H%M%S)
git clone --depth=1 -b main https://github.com/user/repo.git $RELEASE
cd $RELEASE
composer install --no-dev --optimize-autoloader
npm ci && npm run build
ln -s $DEPLOY_PATH/shared/.env $RELEASE/.env
ln -s $DEPLOY_PATH/shared/storage $RELEASE/storage
php artisan migrate --force
php artisan optimize
ln -sfn $RELEASE $DEPLOY_PATH/current
sudo systemctl reload php8.3-fpm nginx
php artisan queue:restart
# Remove old releases
ls -dt $DEPLOY_PATH/releases/* | tail -n +6 | xargs rm -rf
Firewall and Security
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable
ufw status
# Fail2ban
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
systemctl enable --now fail2ban
Monitoring (Minimal)
# Netdata — simple monitoring
bash <(curl -Ss https://my-netdata.io/kickstart.sh)
# Available on :19999
# Or install Prometheus Node Exporter
apt install -y prometheus-node-exporter
Implementation Timeline
- Initial VPS setup + Nginx + PHP + deploy: 1–2 days
- SSL + firewall + fail2ban: several hours
- Monitoring setup: +1 day







