Server provisioning scripts: clean Ubuntu VPS → hardened Coolify + Tailscale + Cloudflare Tunnel in ~15 min #8547
Closed
jroth1111
started this conversation in
Feature Requests
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
The problem
Most Coolify guides end at
curl -fsSL https://get.coolify.io | bash. That gets Coolify running — but it leaves the server in a state few people would accept in production:Closing all of these gaps manually means understanding UFW, iptables DOCKER-USER chains, sshd_config hardening, auditd, fail2ban, sysctl kernel parameters, Tailscale, and Cloudflare Tunnel — then correctly wiring them together. Most guides either skip the hard parts or treat each as a separate tutorial with no automation.
The solution
A set of bash scripts that take a completely clean Ubuntu 24.04 VPS and automate the entire journey — from first SSH to production-ready — in ~15 minutes:
Two entry points — choose based on where you are:
deploy.sh— run from your laptop; give it the VPS IP, root password, Tailscale auth key, and Cloudflare API token. SSHes in and handles everything. No manual server access needed.setup.sh— same, but run directly on the server if you are already SSHed in.Both support interactive (prompt-driven) and non-interactive (
--yes) modes and are idempotent — safe to re-run if interrupted.Inputs
Five things you need before running the script:
203.0.113.1tskey-auth-xxx...coolify.example.comZone:DNS:Edit+Account:Cloudflare Tunnel:EditYour SSH public key is read automatically. All other options (admin username, swap size, deployment mode) have sensible defaults.
Output
Phase progress (
deploy.sh, abridged):Completion summary:
Validation output (
validate_hardening.sh):Security architecture
Before and after
100.x.x.x:8000)Every new app deployed in Coolify automatically gets: auto-assigned subdomain → wildcard DNS → Cloudflare edge SSL → tunnel → Traefik → container. No per-app DNS or TLS configuration needed.
Threat model
tailscale0only; binding-guard timer re-applies on rebootLLM-assisted deployment
The scripts are designed to work with an AI assistant. Share your deployment parameters with Claude, ChatGPT, or another LLM and point it at
AGENTS_DEPLOY.md— it can guide you through or run the entire deployment autonomously:validate_hardening.sh --jsonemits{"pass":N,"fail":N,"checks":[...]}so an LLM can parse results and decide whether to continue or diagnose a failure--ts-ip <ip>resumes from phase 2 if phase 1 already completed, without repeating destructive stepsWhat if something goes wrong?
The most common concern with a script that hardens SSH is getting locked out.
Locked out after hardening? Most VPS providers (Hetzner, DigitalOcean, Linode) offer a web-based console that bypasses network rules entirely. Use that to recover or diagnose.
Lost the Tailscale IP? Check your Tailscale admin panel — the server appears there with its assigned
100.x.x.xaddress. Resume withdeploy.sh --ts-ip <ip>to continue without re-running hardening.UFW blocking something unexpected? Via VPS console:
sudo ufw status numberedto inspect rules, orsudo ufw disableto temporarily drop all rules while you investigate.Important: These scripts are additive only — they do not provide rollback. Snapshot your VPS before running if you want a clean recovery path.
Comparison
Quality
validate_hardening.sh --jsonreports 0 failures across 94 checks on a real serverProposed addition to Coolify repo
Add a
scripts/provisioning/directory alongside the existingscripts/install and upgrade scripts:No PHP, Laravel, Livewire, or database changes. Purely additive bash scripts.
Requirements
Zone:DNS:Edit+Account:Cloudflare Tunnel:EditExisting implementation
Fully implemented and tested against a live deployment: https://github.com/jroth1111/secure_coolify_ubuntu
Note on feature freeze
I understand Coolify is prioritising stability right now. Since this is purely additive — new files in a new directory, touching nothing existing — happy to discuss whether it falls outside the freeze scope, or simply wait for the right window.
Hardening checklist
What validate_hardening.sh checks (94 checks, 0 failures on live deployment)
Time sync
Swap
/swapfilepermissions 0600Service cleanup
rpcbind,avahi-daemon,cupsdisabled and stoppedLogin banner
/etc/issue.netpresentSSH hardening
PasswordAuthentication no)PermitRootLogin no)AllowUsersMatch Addressblock: root login allowed from localhost + Docker bridge only (required for Coolify container→host SSH)Match Addressblock:AllowUsers rootscoped to localhostAuditd
su,useradd,groupadd,passwd,usermod)Kernel hardening (sysctl)
net.ipv4.tcp_syncookies=1— SYN flood protectionnet.ipv4.tcp_max_syn_backlog=2048net.ipv4.tcp_synack_retries=2net.ipv4.conf.all.rp_filter=2— reverse path filteringnet.ipv4.ip_forward=1fs.protected_hardlinks=1fs.protected_symlinks=1fs.suid_dumpable=0kernel.randomize_va_space=2— ASLR full randomisationkernel.yama.ptrace_scope=1— ptrace restrictedkernel.kptr_restrict=2— kernel pointer leak preventionkernel.dmesg_restrict=1kernel.perf_event_paranoid=3kernel.unprivileged_bpf_disabled=1kernel.kexec_load_disabled=1kernel.sysrq=4vm.swappiness=10net.ipv4.tcp_congestion_control=bbr— BBR congestion controlnet.core.default_qdisc=fqUFW firewall
Docker daemon
daemon.jsonpresentlog-driver=json-filewithmax-sizerotationlive-restore=trueDOCKER-USER iptables chain (prevents Docker bypassing UFW)
PartOf=docker.serviceFail2ban
banaction=ufw100.64.0.0/10) inignoreipf2b-sshdiptables chain presentJournald
Unattended-upgrades
Tailscale VPN
tailscale0interface presentBackendState=RunningAdmin user
sudogroupauthorized_keysexists, non-empty, valid formatCoolify dashboard binding
root'sauthorized_keysroot@127.0.0.1SSH functional (required for Coolify deployments)host.docker.internalCloudflare Tunnel (if installed)
cloudflaredservice active/readyendpoint responding/terminal/wspathAppArmor
aa-statusreachableBeta Was this translation helpful? Give feedback.
All reactions