
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
“`bash
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.
“`bash Stuck on a step? Ask a question and the AI answers using this article.
#!/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 <
@ and www pointing to the server IP, Proxied (orange cloud).listen 443 ssl with the certificate paths to the Nginx site, then set SSL mode to Full (strict).6. Keep it healthy
wp db export and a tar of wp-content, keeping a few days — and copy them off the server now and then.free -m and df -h monthly.