
📎 This article includes 1 downloadable practice file ↓
You can run a real website on a cloud server that costs nothing. Oracle Cloud’s Always Free tier includes small virtual machines that are enough for a blog or small shop. This guide is the exact process used for this site.
In this article
What you get for free
- Two small AMD VMs (1 GB RAM each) — or, if capacity is available in your region, Arm VMs with more RAM.
- Around 200 GB of block storage in total and a public IPv4 address per VM.
- A card is needed at sign-up for verification; Always-Free resources are not charged.
1. Create the server
- Compute → Instances → Create instance.
- Image: Ubuntu 24.04. Shape: an Always-Free eligible one.
- Networking: assign a public IPv4 address.
- SSH keys: upload your public key (or let Oracle generate one and download the private key — you cannot get it later).
- Create, and note the public IP.
2. Open ports 80 and 443
Oracle blocks web traffic in two places:
- Security list (VCN → Security Lists → Default → Add Ingress Rules): source
0.0.0.0/0, TCP ports80,443. - The VM’s own iptables — the script below opens them.
3. Connect
ssh -i ~/.ssh/oracle.key ubuntu@YOUR_IP
On Windows the same command works in PowerShell or Git Bash. If it complains about permissions, restrict the key file to your user.
4. The one-command setup
Save this as setup.sh on the server and run sudo bash setup.sh example.com. It is safe to run again.
#!/usr/bin/env bash
# Usage: sudo bash setup.sh example.com
set -euo pipefail
DOMAIN=$1; DB=wp_$(echo "$DOMAIN" | tr '.-' '__'); PASS=$(openssl rand -hex 16)
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq nginx mariadb-server fail2ban unattended-upgrades webp \
php8.3-fpm php8.3-mysql php8.3-gd php8.3-intl php8.3-zip php8.3-curl php8.3-mbstring php8.3-xml php8.3-imagick
# 2 GB swap: essential on 1 GB RAM
[ -f /swapfile ] || { fallocate -l 2G /swapfile; chmod 600 /swapfile; mkswap /swapfile; swapon /swapfile; echo "/swapfile none swap sw 0 0" >> /etc/fstab; }
# open web ports in Oracle's iptables
for p in 80 443; do iptables -C INPUT -p tcp --dport $p -j ACCEPT 2>/dev/null || iptables -I INPUT 5 -p tcp --dport $p -j ACCEPT; done
apt-get install -y -qq iptables-persistent; netfilter-persistent save
# small-server tuning
printf "[mysqld]\ninnodb_buffer_pool_size=96M\nmax_connections=30\nperformance_schema=OFF\n" > /etc/mysql/mariadb.conf.d/99-small.cnf
sed -i 's/^pm = .*/pm = ondemand/; s/^pm.max_children = .*/pm.max_children = 4/' /etc/php/8.3/fpm/pool.d/www.conf
systemctl restart mariadb php8.3-fpm
# database
mariadb -e "CREATE DATABASE IF NOT EXISTS $DB CHARACTER SET utf8mb4; CREATE USER IF NOT EXISTS '$DB'@'localhost' IDENTIFIED BY '$PASS'; GRANT ALL ON $DB.* TO '$DB'@'localhost';"
# WordPress
curl -sSLo /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && chmod +x /usr/local/bin/wp
mkdir -p /var/www/$DOMAIN && chown www-data: /var/www/$DOMAIN
sudo -u www-data wp core download --path=/var/www/$DOMAIN --quiet || true
sudo -u www-data wp config create --path=/var/www/$DOMAIN --dbname=$DB --dbuser=$DB --dbpass=$PASS --quiet --force
# nginx site
cat > /etc/nginx/sites-available/$DOMAIN <<EOF
server {
listen 80; server_name $DOMAIN www.$DOMAIN; root /var/www/$DOMAIN; index index.php;
client_max_body_size 64M;
location / { try_files \$uri \$uri/ /index.php?\$args; }
location ~ \.php\$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.3-fpm.sock; }
location = /xmlrpc.php { deny all; }
}
EOF
ln -sf /etc/nginx/sites-available/$DOMAIN /etc/nginx/sites-enabled/; rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
echo "Done. Open http://$DOMAIN to finish the WordPress install. DB password saved in wp-config.php."
5. Domain and free HTTPS with Cloudflare
- Add your domain to Cloudflare (free plan) and change the nameservers at your registrar.
- DNS: an A record for
@andwwwpointing to the server IP, Proxied (orange cloud). - SSL/TLS: create an Origin Certificate, save it on the server, add
listen 443 sslwith the certificate paths to the Nginx site, then set SSL mode to Full (strict). - Turn on Always Use HTTPS.
6. Keep it healthy
- Backups: a nightly cron with
wp db exportand a tar ofwp-content, keeping a few days — and copy them off the server now and then. - Updates: unattended-upgrades installs security patches automatically.
- Page cache: Nginx FastCGI cache makes a 1 GB server serve pages in about 0.1 s.
- Monitoring: check
free -manddf -hmonthly.
📎 Practice files for this article
- 📄All code from this post2 examples in one file, ready to open in your editor.⬇ SH · 3 KB
Free to use for learning. Files with macros (.bas) are plain text — import them with Alt+F11 → File → Import File, and always test on a copy.
Atul (AJ) builds office-automation and local-first AI tools as Atulya AI, and works with Excel, SAP and Oracle EPM every day. He writes about the shortcuts, macros and automations that actually save time — plus the occasional wacky fact. Videos on YouTube: Lazy Automator AI (@LazyAutomatorAI).
More posts by Atul →Stuck on a step? Ask a question and the AI answers using this article.