mirror of
https://github.com/m1ngsama/automa.git
synced 2026-03-25 18:23:49 +00:00
Merge pull request #7 from m1ngsama/feature/infra-service-deploy-scripts
Add infra service deploy scripts
This commit is contained in:
commit
50ecd7c814
8 changed files with 333 additions and 8 deletions
39
Makefile
39
Makefile
|
|
@ -4,6 +4,7 @@
|
|||
.PHONY: help all status up down logs restart clean minecraft teamspeak nextcloud
|
||||
.PHONY: health health-minecraft health-teamspeak health-nextcloud
|
||||
.PHONY: backup backup-minecraft backup-teamspeak backup-nextcloud backup-list backup-cleanup
|
||||
.PHONY: deploy-email deploy-nginx deploy-ss-server deploy-ss-client deploy-frp-server deploy-frp-client
|
||||
|
||||
# Default target
|
||||
help:
|
||||
|
|
@ -21,6 +22,14 @@ help:
|
|||
@echo " backup-list List available backups"
|
||||
@echo " backup-cleanup Remove old backups"
|
||||
@echo ""
|
||||
@echo "Infrastructure Deploy (set INFRA_DIR first):"
|
||||
@echo " deploy-email Deploy Postfix+Dovecot+OpenDKIM+SpamAssassin"
|
||||
@echo " deploy-nginx Deploy Nginx vhosts"
|
||||
@echo " deploy-ss-server Deploy Shadowsocks server"
|
||||
@echo " deploy-ss-client Deploy Shadowsocks client + privoxy"
|
||||
@echo " deploy-frp-server Deploy FRP server (frps)"
|
||||
@echo " deploy-frp-client Deploy FRP client (frpc)"
|
||||
@echo ""
|
||||
@echo "Service-specific Commands:"
|
||||
@echo " Minecraft:"
|
||||
@echo " minecraft-up Start Minecraft server"
|
||||
|
|
@ -55,6 +64,36 @@ help:
|
|||
@echo " check Check prerequisites"
|
||||
@echo " clean Remove stopped containers and unused volumes"
|
||||
|
||||
# ============================================================================
|
||||
# Infrastructure Service Targets
|
||||
# Requires INFRA_DIR pointing to the corresponding infra module directory.
|
||||
# ============================================================================
|
||||
|
||||
# deploy-email: INFRA_DIR=/path/to/infra/services/email make deploy-email
|
||||
deploy-email:
|
||||
@[ -n "$(INFRA_DIR)" ] || { echo "Set INFRA_DIR=/path/to/infra/services/email"; exit 1; }
|
||||
INFRA_DIR=$(INFRA_DIR) ./services/email/deploy.sh
|
||||
|
||||
deploy-nginx:
|
||||
@[ -n "$(INFRA_DIR)" ] || { echo "Set INFRA_DIR=/path/to/infra/services/nginx"; exit 1; }
|
||||
INFRA_DIR=$(INFRA_DIR) ./services/nginx/deploy.sh
|
||||
|
||||
deploy-ss-server:
|
||||
@[ -n "$(INFRA_DIR)" ] || { echo "Set INFRA_DIR=/path/to/infra/services/shadowsocks/server"; exit 1; }
|
||||
INFRA_DIR=$(INFRA_DIR) ./services/shadowsocks/server/deploy.sh
|
||||
|
||||
deploy-ss-client:
|
||||
@[ -n "$(INFRA_DIR)" ] || { echo "Set INFRA_DIR=/path/to/infra/services/shadowsocks/client"; exit 1; }
|
||||
INFRA_DIR=$(INFRA_DIR) ./services/shadowsocks/client/deploy.sh
|
||||
|
||||
deploy-frp-server:
|
||||
@[ -n "$(INFRA_DIR)" ] || { echo "Set INFRA_DIR=/path/to/infra/services/frp/server"; exit 1; }
|
||||
INFRA_DIR=$(INFRA_DIR) ./services/frp/server/deploy.sh
|
||||
|
||||
deploy-frp-client:
|
||||
@[ -n "$(INFRA_DIR)" ] || { echo "Set INFRA_DIR=/path/to/infra/services/frp/client"; exit 1; }
|
||||
INFRA_DIR=$(INFRA_DIR) ./services/frp/client/deploy.sh
|
||||
|
||||
# Check prerequisites
|
||||
check:
|
||||
@echo "Checking prerequisites..."
|
||||
|
|
|
|||
88
README.md
88
README.md
|
|
@ -1,6 +1,27 @@
|
|||
# Automa
|
||||
|
||||
A collection of self-hosted service automation tools following the Unix philosophy: do one thing well, be composable, and stay simple.
|
||||
Deployment scripts for self-hosted infrastructure. Pairs with [infra](https://github.com/m1ngsama/infra) (private) for configuration.
|
||||
|
||||
```
|
||||
infra/services/<name>/.env → automa/services/<name>/deploy.sh
|
||||
```
|
||||
|
||||
## Relationship with infra
|
||||
|
||||
**infra** (private) holds config templates and `.env.example` files — the "what" and "how to configure".
|
||||
**automa** (public) holds deployment scripts — the "how to deploy". Zero hardcoded values, zero domain names.
|
||||
|
||||
Workflow:
|
||||
1. Clone infra (private), fill in `.env` files for each service you want
|
||||
2. Clone automa (public), run the matching deploy script
|
||||
3. Each script reads `INFRA_DIR` to locate the corresponding `.env`
|
||||
|
||||
```bash
|
||||
# Example
|
||||
cd infra/services/email && cp .env.example .env && $EDITOR .env
|
||||
cd automa/services/email
|
||||
INFRA_DIR=../../infra/services/email ./deploy.sh
|
||||
```
|
||||
|
||||
## Philosophy
|
||||
|
||||
|
|
@ -10,7 +31,49 @@ This project embraces Unix principles:
|
|||
- **Composability**: Tools work together through standard interfaces
|
||||
- **Transparency**: Plain text configuration, readable scripts
|
||||
|
||||
## Services
|
||||
## Infrastructure Services
|
||||
|
||||
System services deployed from infra module configs.
|
||||
|
||||
### Email
|
||||
Postfix + Dovecot + OpenDKIM + SpamAssassin.
|
||||
|
||||
```bash
|
||||
INFRA_DIR=/path/to/infra/services/email ./services/email/deploy.sh
|
||||
```
|
||||
|
||||
### Nginx
|
||||
Web server and reverse proxy vhosts.
|
||||
|
||||
```bash
|
||||
INFRA_DIR=/path/to/infra/services/nginx ./services/nginx/deploy.sh
|
||||
```
|
||||
|
||||
### Shadowsocks
|
||||
GFW-resistant proxy.
|
||||
|
||||
```bash
|
||||
# Server (VPS)
|
||||
INFRA_DIR=/path/to/infra/services/shadowsocks/server ./services/shadowsocks/server/deploy.sh
|
||||
|
||||
# Client (home machine)
|
||||
INFRA_DIR=/path/to/infra/services/shadowsocks/client ./services/shadowsocks/client/deploy.sh
|
||||
```
|
||||
|
||||
### FRP
|
||||
Reverse tunnel — expose home services through VPS.
|
||||
|
||||
```bash
|
||||
# Server (VPS)
|
||||
INFRA_DIR=/path/to/infra/services/frp/server ./services/frp/server/deploy.sh
|
||||
|
||||
# Client (home machine)
|
||||
INFRA_DIR=/path/to/infra/services/frp/client ./services/frp/client/deploy.sh
|
||||
```
|
||||
|
||||
## Home Services
|
||||
|
||||
Docker-based services with their own config.
|
||||
|
||||
### Minecraft Server
|
||||
Automated Minecraft Fabric server deployment with mod management.
|
||||
|
|
@ -72,12 +135,21 @@ Batch clone all repositories from a GitHub organization.
|
|||
|
||||
```
|
||||
automa/
|
||||
├── bin/ # Utility scripts
|
||||
│ └── org-clone.sh # GitHub org repo cloner
|
||||
├── minecraft/ # Minecraft server setup
|
||||
├── teamspeak/ # TeamSpeak server setup
|
||||
├── nextcloud/ # Nextcloud setup
|
||||
└── README.md # This file
|
||||
├── bin/ # Utility scripts
|
||||
│ └── lib/common.sh # Shared logging + env helpers
|
||||
├── services/ # Infrastructure deploy scripts (reads infra .env)
|
||||
│ ├── email/deploy.sh
|
||||
│ ├── nginx/deploy.sh
|
||||
│ ├── shadowsocks/
|
||||
│ │ ├── server/deploy.sh
|
||||
│ │ └── client/deploy.sh
|
||||
│ └── frp/
|
||||
│ ├── server/deploy.sh
|
||||
│ └── client/deploy.sh
|
||||
├── minecraft/ # Minecraft server (Docker)
|
||||
├── teamspeak/ # TeamSpeak server (Docker)
|
||||
├── nextcloud/ # Nextcloud (Docker)
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Common Operations
|
||||
|
|
|
|||
37
services/email/deploy.sh
Executable file
37
services/email/deploy.sh
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
# Deploys Postfix + Dovecot + OpenDKIM + SpamAssassin email stack.
|
||||
# Usage: INFRA_DIR=/path/to/infra/services/email ./deploy.sh
|
||||
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../../bin/lib/common.sh"
|
||||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
|
||||
require_env DOMAIN MAIL_HOST MAIL_USER
|
||||
|
||||
log_info "Installing packages..."
|
||||
apt-get install -y postfix dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd \
|
||||
dovecot-sieve opendkim opendkim-tools spamassassin spamc
|
||||
|
||||
log_info "Deploying Postfix config..."
|
||||
envsubst < "${INFRA_DIR}/postfix/main.cf" > /etc/postfix/main.cf
|
||||
cp "${INFRA_DIR}/postfix/aliases" /etc/aliases
|
||||
newaliases
|
||||
|
||||
log_info "Deploying Dovecot config..."
|
||||
cp "${INFRA_DIR}/dovecot/dovecot.conf" /etc/dovecot/dovecot.conf
|
||||
cp "${INFRA_DIR}/dovecot/99-stats-fix.conf" /etc/dovecot/conf.d/99-stats-fix.conf
|
||||
|
||||
log_info "Adding postfix to dovecot group..."
|
||||
usermod -aG dovecot postfix
|
||||
|
||||
log_info "Enabling services..."
|
||||
systemctl enable --now postfix dovecot opendkim spamassassin
|
||||
|
||||
log_info "Email stack deployed. Remaining manual steps:"
|
||||
echo " 1. Run certbot for mail.${DOMAIN}"
|
||||
echo " 2. Generate DKIM key: opendkim-genkey -b 2048 -d ${DOMAIN} -s mail -D /etc/opendkim/keys/${DOMAIN}/"
|
||||
echo " 3. Add DNS records (see services/email/README.md)"
|
||||
34
services/frp/client/deploy.sh
Executable file
34
services/frp/client/deploy.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env bash
|
||||
# Deploys frpc (FRP client) on home machine.
|
||||
# Usage: INFRA_DIR=/path/to/infra/services/frp/client ./deploy.sh
|
||||
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../../../bin/lib/common.sh"
|
||||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
|
||||
require_env FRP_SERVER_ADDR FRP_SERVER_PORT FRP_TOKEN
|
||||
|
||||
log_info "Downloading FRP..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'][1:])")
|
||||
ARCHIVE="frp_${VERSION}_linux_amd64.tar.gz"
|
||||
wget -q "https://github.com/fatedier/frp/releases/download/v${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
mkdir -p /opt/frp
|
||||
cp "frp_${VERSION}_linux_amd64/frpc" /opt/frp/
|
||||
chmod +x /opt/frp/frpc
|
||||
rm -rf "$ARCHIVE" "frp_${VERSION}_linux_amd64"
|
||||
|
||||
log_info "Deploying config..."
|
||||
envsubst < "${INFRA_DIR}/frpc.toml.example" > /opt/frp/frpc.toml
|
||||
|
||||
log_info "Installing service..."
|
||||
cp "${INFRA_DIR}/frpc.service" /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now frpc
|
||||
|
||||
log_info "FRP client deployed, connecting to ${FRP_SERVER_ADDR}:${FRP_SERVER_PORT}"
|
||||
34
services/frp/server/deploy.sh
Executable file
34
services/frp/server/deploy.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env bash
|
||||
# Deploys frps (FRP server) on VPS.
|
||||
# Usage: INFRA_DIR=/path/to/infra/services/frp/server ./deploy.sh
|
||||
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../../../bin/lib/common.sh"
|
||||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
|
||||
require_env FRP_TOKEN FRP_WEB_PASSWORD FRP_BIND_PORT
|
||||
|
||||
log_info "Downloading FRP..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'][1:])")
|
||||
ARCHIVE="frp_${VERSION}_linux_amd64.tar.gz"
|
||||
wget -q "https://github.com/fatedier/frp/releases/download/v${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
mkdir -p /opt/frp
|
||||
cp "frp_${VERSION}_linux_amd64/frps" /opt/frp/
|
||||
chmod +x /opt/frp/frps
|
||||
rm -rf "$ARCHIVE" "frp_${VERSION}_linux_amd64"
|
||||
|
||||
log_info "Deploying config..."
|
||||
envsubst < "${INFRA_DIR}/frps.toml.example" > /opt/frp/frps.toml
|
||||
|
||||
log_info "Installing service..."
|
||||
cp "${INFRA_DIR}/frps.service" /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now frps
|
||||
|
||||
log_info "FRP server deployed on port ${FRP_BIND_PORT}"
|
||||
36
services/nginx/deploy.sh
Executable file
36
services/nginx/deploy.sh
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
# Deploys Nginx web server and vhost configs.
|
||||
# Usage: INFRA_DIR=/path/to/infra/services/nginx ./deploy.sh
|
||||
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../../bin/lib/common.sh"
|
||||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
|
||||
require_env DOMAIN
|
||||
|
||||
log_info "Installing nginx..."
|
||||
apt-get install -y nginx certbot python3-certbot-nginx
|
||||
|
||||
log_info "Deploying nginx.conf..."
|
||||
cp "${INFRA_DIR}/nginx.conf" /etc/nginx/nginx.conf
|
||||
|
||||
log_info "Deploying vhost configs..."
|
||||
mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
|
||||
|
||||
for conf in "${INFRA_DIR}/sites/"*.conf; do
|
||||
name="$(basename "$conf" .conf)"
|
||||
envsubst < "$conf" > "/etc/nginx/sites-available/${name}"
|
||||
ln -sf "/etc/nginx/sites-available/${name}" "/etc/nginx/sites-enabled/${name}"
|
||||
log_info " Deployed ${name}"
|
||||
done
|
||||
|
||||
log_info "Testing nginx config..."
|
||||
nginx -t
|
||||
|
||||
log_info "Nginx deployed. Remaining manual steps:"
|
||||
echo " 1. Get TLS certs: certbot --nginx -d ${DOMAIN} -d ${CHAN_DOMAIN:-chan.${DOMAIN}} -d ${BLOG_DOMAIN:-blog.${DOMAIN}}"
|
||||
echo " 2. systemctl reload nginx"
|
||||
39
services/shadowsocks/client/deploy.sh
Executable file
39
services/shadowsocks/client/deploy.sh
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
# Installs shadowsocks-rust client (sslocal) + privoxy proxy chain.
|
||||
# Usage: INFRA_DIR=/path/to/infra/services/shadowsocks/client ./deploy.sh
|
||||
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../../../bin/lib/common.sh"
|
||||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
|
||||
require_env SS_SERVER SS_PORT SS_PASSWORD SS_METHOD
|
||||
|
||||
log_info "Downloading shadowsocks-rust client..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])")
|
||||
ARCHIVE="shadowsocks-${VERSION}.x86_64-unknown-linux-gnu.tar.xz"
|
||||
wget -q "https://github.com/shadowsocks/shadowsocks-rust/releases/download/${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
cp sslocal /usr/local/bin/sslocal
|
||||
chmod +x /usr/local/bin/sslocal
|
||||
rm -f "$ARCHIVE" ssserver sslocal ssurl ssmanager redir tunnel
|
||||
|
||||
log_info "Installing privoxy..."
|
||||
apt-get install -y privoxy
|
||||
|
||||
log_info "Deploying configs..."
|
||||
mkdir -p /etc/shadowsocks-rust
|
||||
envsubst < "${INFRA_DIR}/config.json.example" > /etc/shadowsocks-rust/client.json
|
||||
cp "${INFRA_DIR}/privoxy.conf.example" /etc/privoxy/config
|
||||
|
||||
log_info "Installing service..."
|
||||
cp "${INFRA_DIR}/shadowsocks-client.service" /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now shadowsocks-client
|
||||
systemctl enable --now privoxy
|
||||
|
||||
log_info "Proxy chain ready: SOCKS5 at 127.0.0.1:1080, HTTP at 127.0.0.1:8118"
|
||||
34
services/shadowsocks/server/deploy.sh
Executable file
34
services/shadowsocks/server/deploy.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env bash
|
||||
# Installs shadowsocks-rust server and configures systemd service.
|
||||
# Usage: INFRA_DIR=/path/to/infra/services/shadowsocks/server ./deploy.sh
|
||||
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../../../bin/lib/common.sh"
|
||||
|
||||
ENV_FILE="${INFRA_DIR:-.}/.env"
|
||||
[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; }
|
||||
source "$ENV_FILE"
|
||||
|
||||
require_env SS_PORT SS_PASSWORD SS_METHOD
|
||||
|
||||
log_info "Downloading shadowsocks-rust..."
|
||||
VERSION=$(curl -s https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])")
|
||||
ARCHIVE="shadowsocks-${VERSION}.x86_64-unknown-linux-gnu.tar.xz"
|
||||
wget -q "https://github.com/shadowsocks/shadowsocks-rust/releases/download/${VERSION}/${ARCHIVE}"
|
||||
tar -xf "$ARCHIVE"
|
||||
cp ssserver /usr/local/bin/ssserver-rust
|
||||
chmod +x /usr/local/bin/ssserver-rust
|
||||
rm -f "$ARCHIVE" ssserver sslocal ssurl ssmanager redir tunnel
|
||||
|
||||
log_info "Deploying config..."
|
||||
mkdir -p /etc/shadowsocks-rust
|
||||
envsubst < "${INFRA_DIR}/config.json.example" > /etc/shadowsocks-rust/config.json
|
||||
|
||||
log_info "Installing service..."
|
||||
cp "${INFRA_DIR}/shadowsocks-rust.service" /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now shadowsocks-rust
|
||||
|
||||
log_info "Shadowsocks server deployed on port ${SS_PORT}"
|
||||
Loading…
Reference in a new issue