A Bash CLI for deploying Docker Compose services on a VPS with NGINX reverse proxy and automatic Let's Encrypt SSL
With just a few commands you'll have NGINX, SSL certificates, and your Docker services up and running on your VPS.
Clone this repository on your VPS:
git clone git@github.com:parisikosto/vps-stack-mate.git
cd vps-stack-matechmod +x mate.sh && chmod -R +x scripts/./mate.sh generate-config-filesThis creates two files:
.env— service names and Certbot settings. You will be asked for your email address (used for SSL certificate expiry notifications).domains.json— the list of domains to deploy. Edit it with your real domains before deploying.
# Edit domains.json with your real domains
nano domains.json
# Format: a JSON array of domain strings
# ["yourdomain.com", "api.yourdomain.com"]Before deploying, make sure your domains have an A record pointing to your VPS IP. Let's Encrypt needs to reach your server on port 80 to verify ownership.
sudo ./mate.sh deploy-stackThis will:
- Start the NGINX and Certbot containers
- Provision a Let's Encrypt SSL certificate for each domain
- Write the NGINX configs and reload NGINX
Create a docker-compose.override.yml file in the repo root. Docker Compose automatically merges it with docker-compose.yml — no need to edit the base file.
services:
my-service:
container_name: my-service
image: my-image:latest
restart: unless-stoppedFor each domain that should proxy to a service, create a file in nginx/conf/ named after the domain:
nginx/conf/yourdomain.com.conf
Example with proxy_pass:
server {
listen 80;
server_name yourdomain.com;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name yourdomain.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://my-service/;
}
}If no custom conf file exists for a domain, the default template is used (serves static files).
| Situation | Command |
|---|---|
| New domain that needs SSL | sudo ./mate.sh deploy-domains |
| Changed an nginx conf file | sudo ./mate.sh reload-domains |
| Updated a Docker image | ./mate.sh reload-service |
| Added a new service + new domain | sudo ./mate.sh reload-stack |
| Everything from scratch | sudo ./mate.sh deploy-stack |
| Command | Description |
|---|---|
./mate.sh generate-env-file |
Generate the .env file |
./mate.sh generate-domains-file |
Generate the domains.json file |
./mate.sh generate-config-files |
Generate both config files at once |
sudo ./mate.sh deploy-domains |
Provision SSL certs and write nginx configs |
sudo ./mate.sh deploy-services |
Start the Docker Compose stack |
sudo ./mate.sh deploy-stack |
Full deploy: services + domains |
sudo ./mate.sh reload-domains |
Rebuild nginx configs and restart NGINX |
./mate.sh reload-service |
Pull and recreate a single service |
sudo ./mate.sh reload-stack |
Redeploy all services and reload domains |
./mate.sh clean-stack |
Remove generated files (certbot/, nginx/conf.d/, .env, domains.json) |
./mate.sh --help |
Show the help message |
This repository is licensed under the MIT License.
For support and questions, please open an issue in the repository or contact the author directly.