Welcome
This is a collection of personal notes by Ilham Aulia Majid.
π§ VPS Setup Notes
π₯οΈ Base Info
- User:
<your_username>(created by provider) - Purpose: Base secure setup for future use
- Access: via SSH key (no password login)
1. π SSH Setup
Goal: Secure and simplify login.
Steps:
ssh <your_username>@<your_vps_ip>
Local key generated:
ssh-keygen -t ed25519
Key copied to VPS:
ssh-copy-id <your_username>@<your_vps_ip>
SSH config (~/.ssh/config):
Host *
AddKeysToAgent yes
IdentitiesOnly yes
ServerAliveInterval 60
IdentityFile ~/.ssh/id_ed25519
# UseKeychain yes # macOS only
Host github.com
HostName github.com
User git
Host my-vps
HostName <your_vps_ip>
User <your_username>
Port 22
Result β
- Login via:
ssh my-vps - Root login disabled
- Key-only authentication
2. π Firewall (UFW)
Installed and allowed SSH only:
sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status
Result β
- Only port 22 open
- Ping (ICMP) blocked by default
- To allow ping:
sudo ufw allow proto icmp
3. π Timezone Setup
sudo timedatectl set-timezone Asia/Jakarta
timedatectl
Result β
- Server clock set to local time (WIB)
4. π Auto Security Updates
Installed and configured:
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Config file:
/etc/apt/apt.conf.d/50unattended-upgrades
Optional auto-reboot setting:
Unattended-Upgrade::Automatic-Reboot "true";
Logs:
/var/log/unattended-upgrades/unattended-upgrades.log
Result β
- Daily automatic security updates
- Kernel and package updates applied quietly
5. π‘οΈ Fail2Ban
Protects against brute-force attacks by banning IPs with failed login attempts.
Install and enable:
sudo apt install -y fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Check status:
sudo fail2ban-client status
sudo fail2ban-client status sshd
Unban an IP (if needed):
sudo fail2ban-client set sshd unbanip <ip_address>
Optional: Customize settings (only if you want to change defaults)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo vim /etc/fail2ban/jail.local
Example custom settings:
maxretry = 5β Ban after 5 failed attempts (default)bantime = 600β Ban duration in seconds (default: 10 min)findtime = 600β Time window for counting failures (default: 10 min)
Result β
- SSH jail enabled by default
- Automatic IP banning for failed logins
π NGINX Setup Notes
Prerequisites
- Base VPS security setup completed (SSH, UFW, Fail2Ban)
- Domain name pointed to your VPS IP (optional, for production use)
1. π¦ Installation
Install NGINX:
sudo apt update
sudo apt install -y nginx
Check version:
nginx -v
Enable and start service:
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginx
2. π₯ Firewall Rules
Allow HTTP and HTTPS:
sudo ufw allow 'Nginx Full'
Or allow individually:
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
Check firewall status:
sudo ufw status
3. π§ͺ Test Installation
Visit your VPS IP in browser:
http://<your_vps_ip>
You should see the default NGINX welcome page.
4. π Important Directories
- Config files:
/etc/nginx/ - Main config:
/etc/nginx/nginx.conf - Sites available:
/etc/nginx/sites-available/ - Sites enabled:
/etc/nginx/sites-enabled/ - Web root:
/var/www/html/ - Logs:
/var/log/nginx/
5. π§ Basic Server Block (Virtual Host)
Create new site config:
sudo vim /etc/nginx/sites-available/<your_domain>
Basic configuration:
server {
listen 80;
listen [::]:80;
server_name <your_domain>;
root /var/www/<your_domain>;
index index.html;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/<your_domain>.access.log;
error_log /var/log/nginx/<your_domain>.error.log;
}
Create web root directory:
sudo mkdir -p /var/www/<your_domain>
sudo chown -R $USER:$USER /var/www/<your_domain>
Create a test page:
echo "<h1>Welcome to <your_domain></h1>" > /var/www/<your_domain>/index.html
Enable the site:
sudo ln -s /etc/nginx/sites-available/<your_domain> /etc/nginx/sites-enabled/
Test configuration:
sudo nginx -t
Reload NGINX:
sudo systemctl reload nginx
6. π Reverse Proxy (Optional)
For apps running on localhost:
server {
listen 80;
server_name <your_domain>;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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;
}
}
7. π SSL with Letβs Encrypt
Install Certbot:
sudo apt install -y certbot python3-certbot-nginx
Get SSL certificate for a domain:
sudo certbot --nginx -d <your_domain>
For multiple domains/subdomains at once:
sudo certbot --nginx -d example.com -d www.example.com -d api.example.com
Adding SSL to a new subdomain later:
sudo certbot --nginx -d new-subdomain.example.com
Auto-renewal is enabled by default. Test it:
sudo certbot renew --dry-run
List all certificates:
sudo certbot certificates
8. π οΈ Common Commands
# Test configuration
sudo nginx -t
# Reload (graceful, no downtime)
sudo systemctl reload nginx
# Restart
sudo systemctl restart nginx
# Stop
sudo systemctl stop nginx
# View access logs
sudo tail -f /var/log/nginx/access.log
# View error logs
sudo tail -f /var/log/nginx/error.log
Result β
- NGINX installed and running
- Firewall configured for web traffic
- Ready to serve websites or act as reverse proxy
π Headscale Setup Notes
Prerequisites
- Base VPS security setup completed
- NGINX installed and configured
- Domain pointed to VPS IP
- Port 443 available
1. π¦ Installation
Download latest release:
cd /tmp
wget https://github.com/juanfont/headscale/releases/latest/download/headscale_<version>_linux_amd64.deb
Install:
sudo apt install ./headscale_*_linux_amd64.deb
Verify installation:
headscale version
2. βοΈ Configuration
Copy your config to the correct location:
sudo cp headscale.config.yaml /etc/headscale/config.yaml
sudo chown headscale:headscale /etc/headscale/config.yaml
sudo chmod 644 /etc/headscale/config.yaml
Review and edit config as needed:
sudo vim /etc/headscale/config.yaml
Important: Disable built-in ACME (nginx will handle SSL):
acme_email: ""
tls_letsencrypt_hostname: ""
tls_letsencrypt_listen: ""
Create data directory:
sudo mkdir -p /var/lib/headscale
sudo chown headscale:headscale /var/lib/headscale
3. π NGINX Reverse Proxy (HTTP Only - Temporary)
Create nginx config:
sudo vim /etc/nginx/sites-available/<your_domain>
Add basic HTTP configuration:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name <your_domain>;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $server_name;
proxy_buffering off;
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;
}
}
Enable site:
sudo ln -s /etc/nginx/sites-available/<your_domain> /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
4. π SSL Certificate
Get certificate (certbot will auto-configure HTTPS):
sudo certbot --nginx -d <your_domain>
5. π Start Service
Enable and start:
sudo systemctl enable headscale
sudo systemctl start headscale
Check status:
sudo systemctl status headscale
sudo journalctl -u headscale -f
Note: You may see a warning βListening without TLS but ServerURL does not start with http://β - this is expected when using nginx as reverse proxy.
6. π₯ User Management
Create a user:
sudo headscale users create <username>
List users:
sudo headscale users list
7. π± Connect Devices
Generate registration key:
sudo headscale preauthkeys create --user <username> --expiration 1h
On client device:
tailscale up --login-server https://<your_domain> --authkey <key>
List connected nodes:
sudo headscale nodes list
8. π Exit Node Setup (Optional)
Configure the VPS to act as an exit node for routing traffic.
Install Tailscale client on VPS:
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/noble.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/noble.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt update
sudo apt install -y tailscale
Enable IP forwarding:
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Allow forwarding in firewall:
sudo ufw allow in on tailscale0
sudo ufw route allow in on tailscale0
Generate auth key for VPS:
sudo headscale preauthkeys create --user <username> --expiration 1h
Connect VPS to headscale and advertise as exit node:
sudo tailscale up --login-server https://<your_domain> --advertise-exit-node --authkey <key>
9. π οΈ Common Commands
# List all nodes
sudo headscale nodes list
# List users
sudo headscale users list
# Create preauth key
sudo headscale preauthkeys create --user <username>
# Remove node
sudo headscale nodes delete --identifier <node-id>
# Service management
sudo systemctl status headscale
sudo systemctl restart headscale
sudo journalctl -u headscale -n 50
Result β
- Headscale running with SSL
- Ready to accept Tailscale clients
- Self-hosted VPN control server