This guide walks through every step needed to put PDFTools live at
https://pdf-tools.techscript.ca using GoDaddy as your DNS registrar.
Use this section if your site is hosted on GitHub Pages (the default for this repo). The rest of the document describes a self-hosted VPS deployment.
GitHub Pages serves subdomains via a CNAME record, not an A record.
pdf-tools record if one already exists).Fill in the form exactly as shown:
| Field | Value |
|---|---|
| Type | CNAME |
| Name | pdf-tools |
| Value | ppsk2011.github.io |
| TTL | 600 seconds (10 min) |
Important: Delete any existing
AorAAAArecord forpdf-toolsbefore (or instead of) adding the CNAME, as conflicting record types will cause the DNS check to fail.
The repository root must contain a file named CNAME with exactly this content:
pdf-tools.techscript.ca
This file already exists in the repo at /CNAME. GitHub Pages reads it to
confirm the custom domain and complete the DNS verification.
pdf-tools.techscript.ca.# From any terminal — should return "ppsk2011.github.io" once propagated
dig pdf-tools.techscript.ca CNAME +short
# Online checker
# https://www.whatsmydns.net/#CNAME/pdf-tools.techscript.ca
| Requirement | Details |
|---|---|
| GoDaddy account | You own techscript.ca and can edit its DNS |
| VPS / cloud server | Ubuntu 22.04 recommended (DigitalOcean, Hetzner, AWS EC2, etc.) |
| Server public IPv4 | Note it from your hosting provider’s dashboard |
| Open ports on server | TCP 22 (SSH), 80 (HTTP), 443 (HTTPS) |
What you’re doing: telling the internet that
pdf-tools.techscript.cashould resolve to your server’s IP address.
Fill in the form:
| Field | Value |
|---|---|
| Type | A |
| Name | pdf-tools |
| Value | YOUR_SERVER_IP (e.g. 165.232.100.42) |
| TTL | 600 seconds (10 min) — lower = faster propagation |
If GoDaddy shows a CNAME option instead of A: use
Abecause you have a fixed IP. If your host gives you a hostname (e.g. Vercel / Railway), useCNAMEwith that hostname as the value and setName = pdf-tools.
Changes take a few minutes to up to 48 hours to propagate. Check with:
# From your local machine or any terminal
nslookup pdf-tools.techscript.ca
# Should print YOUR_SERVER_IP once propagated
# Or use the online checker
# https://www.whatsmydns.net/#A/pdf-tools.techscript.ca
SSH into your server and install the required software:
ssh root@YOUR_SERVER_IP
# Update packages
apt update && apt upgrade -y
# Install Docker + Docker Compose plugin
curl -fsSL https://get.docker.com | sh
apt install -y docker-compose-plugin
# Install nginx + Certbot (for free SSL)
apt install -y nginx certbot python3-certbot-nginx
# Verify installations
docker --version
nginx -v
certbot --version
# Set up firewall — allow only SSH, HTTP, HTTPS; block direct container ports
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw deny 3000/tcp # frontend container — nginx proxies this
ufw deny 3001/tcp # backend container — nginx proxies this
ufw deny 6379/tcp # Redis — internal only
ufw --force enable
# Clone the repository
git clone https://github.com/ppsk2011/pdf-tools.git
cd pdf-tools
# Create the backend environment file
cp backend/.env.example backend/.env
nano backend/.env
Set these values in backend/.env:
PORT=3001
NODE_ENV=production
FRONTEND_URL=https://pdf-tools.techscript.ca
REDIS_URL=redis://redis:6379
MAX_FILE_SIZE=104857600
FILE_TTL_MS=1800000
# Optional — only needed if you use the donation feature
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
Use the production override file so the app is built for your subdomain:
docker compose \
-f docker-compose.yml \
-f docker-compose.prod.yml \
up --build -d
This starts three containers:
| Container | Role | Internal port |
|—|—|—|
| frontend | React SPA (nginx static) | 3000 |
| backend | Node.js / Express API | 3001 |
| redis | Job queue & cache | 6379 (internal only) |
Verify all containers are healthy:
docker compose ps
# All three should show "Up" or "(healthy)"
nginx needs to be running so Certbot can complete the ACME domain challenge. We’ll start with a minimal HTTP-only config, get the certificate, then switch to the full production config.
# Write a minimal bootstrap config (HTTP only — no SSL lines yet)
cat > /etc/nginx/sites-available/pdf-tools.techscript.ca << 'EOF'
server {
listen 80;
server_name pdf-tools.techscript.ca;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
EOF
# Enable the site and remove the default placeholder
ln -s /etc/nginx/sites-available/pdf-tools.techscript.ca \
/etc/nginx/sites-enabled/pdf-tools.techscript.ca
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
certbot --nginx \
-d pdf-tools.techscript.ca \
--email you@techscript.ca \
--agree-tos \
--no-eff-email
Certbot automatically:
Once the certificate is issued, swap the minimal config for the production-ready one (which includes security headers, gzip, and proper proxy settings):
# Copy the full production nginx config from the repo
cp nginx/pdf-tools.techscript.ca.conf /etc/nginx/sites-available/pdf-tools.techscript.ca
nginx -t && systemctl reload nginx
certbot renew --dry-run
# Should say "No renewals were attempted" (cert is still fresh)
After Certbot runs, reload nginx one final time:
nginx -t && systemctl reload nginx
Run this checklist from your local machine:
# 1. DNS resolves to your server
dig pdf-tools.techscript.ca A +short
# → YOUR_SERVER_IP
# 2. HTTP redirects to HTTPS
curl -I http://pdf-tools.techscript.ca
# → 301 Moved Permanently to https://...
# 3. Frontend loads (HTTP 200 over HTTPS)
curl -I https://pdf-tools.techscript.ca
# → HTTP/2 200
# 4. Backend health check works
curl https://pdf-tools.techscript.ca/health
# → {"status":"ok","env":"production",...}
# 5. SSL grade
# Open in browser: https://www.ssllabs.com/ssltest/analyze.html?d=pdf-tools.techscript.ca
# Should score A or A+
# 6. Security headers
curl -I https://pdf-tools.techscript.ca | grep -i "strict-transport\|x-frame\|x-content"
Then open https://pdf-tools.techscript.ca in your browser — you should
see the PDFTools homepage over HTTPS with a padlock icon. 🎉
cd ~/pdf-tools
git pull origin main
docker compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d
docker compose logs -f backend # API logs
docker compose logs -f frontend # nginx (frontend) logs
docker compose restart backend
docker compose down
| Type | Name | Value | TTL |
|---|---|---|---|
A |
pdf-tools |
YOUR_SERVER_IP |
600 |
That single record is all GoDaddy needs. Everything else (SSL, routing, CORS, etc.) is handled on the server side.