← All articles
Self-hostingConfiguration

Paperclip SSL Setup: HTTPS with Let's Encrypt

Running Paperclip over plain HTTP is fine for local development, but any production instance needs HTTPS. Certbot and Let's Encrypt give you free, auto-renewing SSL certificates in minutes.

Deploy on Railway instead →

Prerequisites

  • A domain name pointing to your server's IP (A record set and propagated)
  • nginx installed and running
  • Port 80 and 443 open in your firewall

Step 1: Install Certbot

sudo apt install -y certbot python3-certbot-nginx

Step 2: Obtain a certificate

Make sure nginx is running with a basic HTTP config for your domain first. Then run:

sudo certbot --nginx -d paperclip.yourdomain.com

Certbot will:

  1. Verify domain ownership via HTTP challenge
  2. Issue the certificate
  3. Automatically update your nginx config with SSL settings
  4. Redirect HTTP to HTTPS

Follow the prompts — enter your email for renewal notices and agree to the terms of service.

Step 3: Verify

sudo nginx -t && sudo systemctl reload nginx

Open https://paperclip.yourdomain.com in your browser. You should see the green padlock.

What Certbot adds to nginx

After running certbot, your nginx server block will have these additions:

ssl_certificate /etc/letsencrypt/live/paperclip.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/paperclip.yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

And a redirect server block:

server {
    listen 80;
    server_name paperclip.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

Don't remove these — they're what makes HTTPS work.

Step 4: Set up auto-renewal

Let's Encrypt certificates expire every 90 days. Certbot installs a systemd timer that renews them automatically.

Verify the timer is active:

sudo systemctl status certbot.timer

Test renewal without actually renewing:

sudo certbot renew --dry-run

If the dry run succeeds, auto-renewal is working. You won't need to do anything manually.

Multiple domains

To add multiple domains to the same certificate:

sudo certbot --nginx -d paperclip.yourdomain.com -d www.paperclip.yourdomain.com

Or add an additional domain to an existing cert:

sudo certbot --nginx -d paperclip.yourdomain.com -d another.yourdomain.com --expand

Wildcard certificates

For *.yourdomain.com wildcard certificates, use the DNS challenge instead of HTTP:

sudo certbot certonly --manual \
  --preferred-challenges=dns \
  -d *.yourdomain.com \
  -d yourdomain.com

This requires adding a TXT record to your DNS, then press Enter. Useful if you're managing multiple subdomains.

Manual nginx SSL (without Certbot)

If you have your own certificate (e.g., from ZeroSSL or a paid CA), configure nginx manually:

server {
    listen 443 ssl http2;
    server_name paperclip.yourdomain.com;

    ssl_certificate /path/to/your/fullchain.pem;
    ssl_certificate_key /path/to/your/private.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # ... rest of your config
}

HTTPS behind a load balancer

If your server is behind a load balancer that terminates SSL (AWS ALB, Cloudflare, etc.), configure Paperclip to trust forwarded headers:

# Set this if Paperclip is behind a proxy that adds X-Forwarded-Proto
PAPERCLIP_TRUST_PROXY=true

Also set in nginx:

proxy_set_header X-Forwarded-Proto $scheme;

This tells Paperclip the connection is HTTPS even though the server-side connection is HTTP.

Common errors

Challenge failed (HTTP 404): nginx isn't configured for your domain yet, or the A record hasn't propagated. Check: curl http://paperclip.yourdomain.com — does it reach your server?

Connection timed out during challenge: Port 80 is blocked by your firewall. Run: sudo ufw allow 80

Certificate already exists but is expired: Run sudo certbot renew --force-renewal

ssl_dhparam file missing: Generate it: openssl dhparam -out /etc/letsencrypt/ssl-dhparams.pem 2048 (takes a few minutes)

Checking certificate expiry

sudo certbot certificates

Shows all certificates, their domains, and expiry dates.

Check a specific domain:

echo | openssl s_client -connect paperclip.yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates

Cloudflare as an alternative

If your DNS is on Cloudflare, you can use Cloudflare's free SSL instead of Let's Encrypt. Set the SSL mode to Full (strict) and Cloudflare handles certificate management. Your server still needs a certificate (can be self-signed since Cloudflare terminates at the edge), or use Cloudflare's origin certificate.

Managed platforms like Railway handle all of this automatically — no SSL configuration needed.

Ready to deploy?

Affiliate disclosure: this link may earn us a commission at no extra cost to you.

This is an independent guide. Paperclip Hosting is not affiliated with the official Paperclip project. Guide steps are based on real deployments and are subject to change as the software evolves.