−25%

στα Windows με ετήσια χρέωση, έως 31/10. Δείτε τα πακέτα

EQVPS
Ξεκινήστε

VPS για προεπισκοπήσεις πρακτόρων κώδικα: κάθε branch που στέλνει ο πράκτορας παίρνει δικό του URL

Ένας πράκτορας κώδικα τελειώνει ένα branch και λέει ότι δουλεύει. Δώστε του έναν server όπου μπορεί να ελεγχθεί: κάθε branch χτίζεται σε container και ανοίγει σε δικό του υποτομέα HTTPS πίσω από κωδικό, και το κλειδί SSH του πράκτορα μπορεί μόνο να ξεκινά και να σταματά προεπισκοπήσεις.

Ένας πράκτορας κώδικα λέει ότι η λειτουργία δουλεύει. Ίσως να ισχύει. Τα τεστ που έγραψε περνάνε, και αυτό αποδεικνύει λιγότερα απ' όσα θα θέλαμε όλοι. Αυτό που πραγματικά θέλετε είναι να το ανοίξετε στον browser πριν πλησιάσει τους χρήστες, χωρίς να ζητήσετε από τον πράκτορα να αγγίξει την παραγωγή.

Τα περιβάλλοντα προεπισκόπησης το λύνουν, και δεν χρειάζεστε πλατφόρμα γι' αυτά. Ένας VPS με δική του IPv4, Docker, Caddy και δύο σύντομα scripts δίνουν σε κάθε branch δικό του URL, όπως https://feature-login-form.preview.example.com, πίσω από κωδικό και με νέο build σε κάθε push. Ο πράκτορας παίρνει ένα κλειδί SSH που μπορεί να ξεκινά και να σταματά προεπισκοπήσεις και τίποτε άλλο.

Το στήσαμε σε server δοκιμών και περάσαμε όλο τον κύκλο πριν το γράψουμε: δημιουργία, άνοιγμα, νέο push, κατάργηση, απόπειρα κατάχρησης του κλειδιού.

Τι χρειάζεστε

  • Έναν VPS με δημόσια IPv4. Το AI-Agent-IP χωράει αρκετές προεπισκοπήσεις ταυτόχρονα.
  • Μια wildcard εγγραφή DNS: *.preview.example.com → η IP του server.
  • Το αποθετήριο της εφαρμογής σας με ένα Dockerfile που σερβίρει στη θύρα 8080. Οποιαδήποτε γλώσσα κάνει.
  • Ubuntu 24.04 ή Debian 12/13 με apt install -y docker.io caddy git.

Κλωνοποιήστε το αποθετήριο μία φορά στο /srv/app, με deploy key μόνο ανάγνωσης.

Τα δύο scripts

Το /usr/local/bin/preview-up χτίζει ένα branch και το βάζει online:

#!/usr/bin/env bash
# preview-up <branch> — build the branch and open it at https://<name>.preview.example.com
set -euo pipefail
BRANCH="$1"
NAME=$(printf '%s' "$BRANCH" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9' '-' | sed 's/--*/-/g; s/^-//; s/-$//' | cut -c1-40)
DIR=/srv/previews/$NAME
git -C /srv/app fetch --quiet origin "$BRANCH"
rm -rf "$DIR"; git -C /srv/app worktree prune
git -C /srv/app worktree add --quiet --force --detach "$DIR" FETCH_HEAD
docker build --quiet -t "preview-$NAME" "$DIR" >/dev/null
docker rm -f "preview-$NAME" >/dev/null 2>&1 || true
docker run -d --name "preview-$NAME" --restart unless-stopped --memory 512m -p 127.0.0.1::8080 "preview-$NAME" >/dev/null
PORT=$(docker port "preview-$NAME" 8080/tcp | head -1 | awk -F: '{print $NF}')
cat > "/etc/caddy/previews/$NAME.caddy" <<CADDY
$NAME.preview.example.com {
	import preview_common
	reverse_proxy 127.0.0.1:$PORT
}
CADDY
systemctl reload caddy
echo "https://$NAME.preview.example.com"

Το /usr/local/bin/preview-down το αφαιρεί:

#!/usr/bin/env bash
# preview-down <branch> — remove the branch preview
set -euo pipefail
NAME=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9' '-' | sed 's/--*/-/g; s/^-//; s/-$//' | cut -c1-40)
docker rm -f "preview-$NAME" >/dev/null 2>&1 || true
docker image rm "preview-$NAME" >/dev/null 2>&1 || true
rm -f "/etc/caddy/previews/$NAME.caddy"; rm -rf "/srv/previews/$NAME"; git -C /srv/app worktree prune
systemctl reload caddy

Μερικές επιλογές είναι σκόπιμες. Τα containers δημοσιεύουν μόνο στο 127.0.0.1 με τυχαία θύρα, οπότε τίποτα δεν φτάνει σε αυτά παρά μόνο μέσω Caddy. Αυτό μετράει, γιατί οι θύρες που δημοσιεύει το Docker παρακάμπτουν το ufw. Κάθε προεπισκόπηση έχει όριο μνήμης 512 MB, ώστε ένα branch εκτός ελέγχου να μη ρίξει τα υπόλοιπα. Και αν τρέξετε ξανά το ίδιο branch, ξαναχτίζεται επί τόπου: push, up, ανανέωση.

Caddy: ένα αρχείο ανά προεπισκόπηση, ένας κωδικός για όλες

mkdir -p /etc/caddy/previews /srv/previews
chmod +x /usr/local/bin/preview-up /usr/local/bin/preview-down
caddy hash-password --plaintext 'choose-a-review-password'

Βάλτε το hash στο /etc/caddy/Caddyfile:

(preview_common) {
	basicauth {
		reviewer PASTE-THE-HASH-HERE
	}
}
import /etc/caddy/previews/*.caddy

Μετά systemctl reload caddy. Κάθε προεπισκόπηση βρίσκεται πλέον πίσω από την ίδια σύνδεση, οπότε ένα μισοτελειωμένο branch με έξοδο debug δεν μένει ανοιχτό στο internet. Σε νεότερες εκδόσεις του Caddy η οδηγία γράφεται και basic_auth· το basicauth δουλεύει ακόμη και στις δύο.

Το κλειδί του πράκτορα: up και down, τίποτε άλλο

Ο πράκτορας πρέπει να ξεκινά προεπισκοπήσεις, όχι να κατέχει τον server. Δημιουργήστε χρήστη deploy και ένα script-φύλακα που δέχεται ακριβώς δύο εντολές:

#!/usr/bin/env bash
# /usr/local/bin/preview-gate — the only thing the agent's key may run
set -euo pipefail
read -r ACTION BRANCH EXTRA <<< "${SSH_ORIGINAL_COMMAND:-}"
[[ -z "${EXTRA:-}" && "${BRANCH:-}" =~ ^[A-Za-z0-9][A-Za-z0-9._/-]{0,99}$ && "$BRANCH" != *..* ]] || { echo "usage: up|down <branch>" >&2; exit 2; }
case "$ACTION" in
  up)   exec sudo /usr/local/bin/preview-up "$BRANCH" ;;
  down) exec sudo /usr/local/bin/preview-down "$BRANCH" ;;
  *)    echo "usage: up|down <branch>" >&2; exit 2 ;;
esac
useradd -m -s /bin/bash deploy
echo 'deploy ALL=(root) NOPASSWD: /usr/local/bin/preview-up, /usr/local/bin/preview-down' > /etc/sudoers.d/preview
chmod 440 /etc/sudoers.d/preview && visudo -cf /etc/sudoers.d/preview
chmod 755 /usr/local/bin/preview-gate

Στο /home/deploy/.ssh/authorized_keys, δέστε το δημόσιο κλειδί του πράκτορα σε αυτό το script:

restrict,command="/usr/local/bin/preview-gate" ssh-ed25519 AAAA... coding-agent

Από το μηχάνημα όπου δουλεύει ο πράκτορας:

ssh deploy@preview.example.com up feature/login-form
# https://feature-login-form.preview.example.com
ssh deploy@preview.example.com down feature/login-form

Στη δοκιμή μας, το up έχτισε και δημοσίευσε το branch, ένα δεύτερο up μετά από νέο commit σέρβιρε τη νέα έκδοση, και το down αφαίρεσε το container και το site. Απόπειρες με cat /etc/shadow, up x; id, ονόματα branch όπως -x ή a/../b, ή διαδραστική σύνδεση με αυτό το κλειδί πήραν μόνο usage: up|down <branch>. Ένα όνομα branch πρέπει να ξεκινά με γράμμα ή ψηφίο και δεν μπορεί να περιέχει ...

Σύνδεση με τον πράκτορα

Με Claude Code ή Codex αρκεί μία γραμμή στο αρχείο οδηγιών του έργου:

Αφού κάνεις push ένα branch, τρέξε ssh deploy@preview.example.com up <branch> και βάλε το URL που τυπώνεται στη σύνοψή σου. Τρέξε down όταν το branch συγχωνευτεί ή εγκαταλειφθεί.

Αν το CI σας τρέχει ήδη σε κάθε push, καλέστε την ίδια εντολή από εκεί και κρατήστε το κλειδί εντελώς έξω από το περιβάλλον του πράκτορα. Είναι η αυστηρότερη επιλογή, και θα τη διαλέγαμε για οτιδήποτε πέρα από ένα προσωπικό έργο.

Τι να προσέχετε

  • Δίσκος. Κάθε build αφήνει layers εικόνων. Ένα εβδομαδιαίο cron με docker image prune -f το κρατά υπό έλεγχο· το down σβήνει ήδη την εικόνα της ίδιας της προεπισκόπησης.
  • Branches που κανείς δεν κλείνει. Οι πράκτορες ανοίγουν περισσότερα branches από τους ανθρώπους. Ένα cron που απαριθμεί containers preview-* παλαιότερα της εβδομάδας και τρέχει preview-down σε αυτά σας γλιτώνει από είκοσι ξεχασμένες προεπισκοπήσεις.
  • Μυστικά. Οι προεπισκοπήσεις πρέπει να τρέχουν με δοκιμαστικά διαπιστευτήρια. Ο κωδικός basic auth κρατά τους ξένους έξω· δεν κάνει αποδεκτό να συνδέσετε μια προεπισκόπηση με τη βάση παραγωγής.
  • Χρόνος build. Οι εικόνες χτίζονται στον server, οπότε ένα βαρύ build ανταγωνίζεται για CPU τις προεπισκοπήσεις που τρέχουν. Αν τα builds κρατούν λεπτά, χτίστε στο CI και κατεβάστε την εικόνα.

Ο ίδιος ο πράκτορας δεν χρειάζεται να ζει σε αυτόν τον server. Αν ζει, δείτε το VPS για Claude Code, και για να παραγγέλνει και να φροντίζει μόνος του αυτόν τον server, συνδέστε τον με τον MCP server της EQVPS. Το ίδιο μηχάνημα μπορεί να φιλοξενεί και το MCP gateway της ομάδας σας. Για μη αξιόπιστο κώδικα χωρίς καθόλου server υπάρχουν τα sandbox, και τα πακέτα με δική τους IPv4 ξεκινούν από $8 τον μήνα.

Συχνές ερωτήσεις

Γιατί να μην αφήσουμε τον πράκτορα να κάνει deploy κατευθείαν στην παραγωγή;

Γιατί το «περνάνε τα τεστ» και το «δουλεύει» δεν είναι το ίδιο, και ο πράκτορας πρέπει να είναι ο τελευταίος που το αποφασίζει. Μια προεπισκόπηση δίνει σε έναν άνθρωπο κάτι να ανοίξει πριν φτάσει οτιδήποτε στους χρήστες, με κόστος μία επιπλέον εντολή.

Ποιο πακέτο ταιριάζει;

Εξαρτάται από το πόσες προεπισκοπήσεις τρέχουν ταυτόχρονα. Το AI-Agent-IP ($15/μήνα, 4 vCPU, 4 GB RAM, 40 GB δίσκος) χωράει άνετα αρκετές μικρές web εφαρμογές με όριο 512 MB η καθεμία. Τα builds του Docker είναι το βαρύτερο κομμάτι, οπότε προσέξτε δίσκο και μνήμη αν οι εικόνες σας είναι μεγάλες.

Χρειάζομαι wildcard πιστοποιητικό;

Όχι. Το Caddy παίρνει μόνο του ξεχωριστό πιστοποιητικό για κάθε υποτομέα προεπισκόπησης. Μόνο η εγγραφή DNS είναι wildcard. Το Let's Encrypt επιτρέπει περίπου 50 νέα πιστοποιητικά ανά καταχωρημένο τομέα την εβδομάδα, υπεραρκετά εκτός αν ο πράκτορας φτιάξει εκατοντάδες branches.

Μπορεί ο πράκτορας να χαλάσει τον server με το κλειδί SSH του;

Όχι με αυτό το κλειδί. Περιορίζεται σε μία εντολή που δέχεται μόνο «up <branch>» ή «down <branch>» με ασφαλές όνομα branch. Πρόσβαση σε shell, επιπλέον ορίσματα και προώθηση θυρών απορρίπτονται.

Δουλεύει σε πακέτο NAT;

Όχι. Οι προεπισκοπήσεις πρέπει να είναι προσβάσιμες στις θύρες 80 και 443 στους δικούς τους υποτομείς, κάτι που απαιτεί δημόσια IPv4. Τα πακέτα NAT προωθούν μόνο τη θύρα SSH.

Σχόλια

Δεν υπάρχουν ακόμη σχόλια. Γίνετε ο πρώτος.

Αφήστε ένα σχόλιο

Τα σχόλια ελέγχονται πριν εμφανιστούν.