| @@ -10,8 +10,8 @@ | |||
| 10 | 10 | # wp-content/uploads writable by the web server group (775 dirs / 664 files) with --group-write | |
| 11 | 11 | # | |
| 12 | 12 | # Run from a URL (pass options after "bash -s --"): | |
| 13 | - | # curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions | bash -s -- --dry-run | |
| 14 | - | # curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions | sudo bash -s -- -p /var/www/example.com -o deploy -g www-data --group-write | |
| 13 | + | # curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions/raw/HEAD/fix-wp-permissions.sh | bash -s -- --dry-run | |
| 14 | + | # curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions/raw/HEAD/fix-wp-permissions.sh | sudo bash -s -- -p /var/www/example.com -o deploy -g www-data --group-write | |
| 15 | 15 | # | |
| 16 | 16 | # Or locally: | |
| 17 | 17 | # ./fix-wp-permissions.sh [-p path] [-o owner] [-g group] [--group-write] [--strict] [--dry-run] | |
| @@ -43,7 +43,7 @@ Usage: fix-wp-permissions.sh [options] | |||
| 43 | 43 | -h, --help show this help | |
| 44 | 44 | ||
| 45 | 45 | From a URL: | |
| 46 | - | curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions | bash -s -- --dry-run | |
| 46 | + | curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions/raw/HEAD/fix-wp-permissions.sh | bash -s -- --dry-run | |
| 47 | 47 | USAGE | |
| 48 | 48 | exit "${1:-0}" | |
| 49 | 49 | } | |
Veruse / fix-wp-permissions.sh
Last active 3 weeks ago
bash <(curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions/raw/HEAD/fix-wp-permissions.sh)
Veruse revised this gist 3 weeks ago · 9e65b5e
1 file changed, 3 insertions, 3 deletions
Veruse revised this gist 3 weeks ago · 20a1a21
1 file changed, 155 insertions
| @@ -0,0 +1,155 @@ | |||
| 1 | + | #!/usr/bin/env bash | |
| 2 | + | # | |
| 3 | + | # fix-wp-permissions.sh — reset file and folder permissions on a WordPress install. | |
| 4 | + | # | |
| 5 | + | # Defaults (WordPress-recommended): | |
| 6 | + | # directories 755 | |
| 7 | + | # files 644 | |
| 8 | + | # wp-config.php 640 (use --strict for 600) | |
| 9 | + | # .htaccess 644 | |
| 10 | + | # wp-content/uploads writable by the web server group (775 dirs / 664 files) with --group-write | |
| 11 | + | # | |
| 12 | + | # Run from a URL (pass options after "bash -s --"): | |
| 13 | + | # curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions | bash -s -- --dry-run | |
| 14 | + | # curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions | sudo bash -s -- -p /var/www/example.com -o deploy -g www-data --group-write | |
| 15 | + | # | |
| 16 | + | # Or locally: | |
| 17 | + | # ./fix-wp-permissions.sh [-p path] [-o owner] [-g group] [--group-write] [--strict] [--dry-run] | |
| 18 | + | # | |
| 19 | + | # With no -p, the current directory is used. | |
| 20 | + | ||
| 21 | + | # Everything runs inside main(), called on the last line, so a partially | |
| 22 | + | # downloaded script never executes. | |
| 23 | + | main() { | |
| 24 | + | set -euo pipefail | |
| 25 | + | ||
| 26 | + | WP_PATH="$PWD" | |
| 27 | + | OWNER="" | |
| 28 | + | GROUP="" | |
| 29 | + | GROUP_WRITE=false | |
| 30 | + | STRICT=false | |
| 31 | + | DRY_RUN=false | |
| 32 | + | ||
| 33 | + | usage() { | |
| 34 | + | cat <<'USAGE' | |
| 35 | + | Usage: fix-wp-permissions.sh [options] | |
| 36 | + | ||
| 37 | + | -p, --path DIR WordPress root (default: current directory) | |
| 38 | + | -o, --owner USER chown files to USER (needs root) | |
| 39 | + | -g, --group GROUP chown files to GROUP, e.g. www-data (needs root) | |
| 40 | + | --group-write make wp-content/uploads writable by the group (775/664) | |
| 41 | + | --strict wp-config.php 600 instead of 640 | |
| 42 | + | -n, --dry-run show what would change, change nothing | |
| 43 | + | -h, --help show this help | |
| 44 | + | ||
| 45 | + | From a URL: | |
| 46 | + | curl -fsSL https://gist.veru.se/Veruse/fix-wp-permissions | bash -s -- --dry-run | |
| 47 | + | USAGE | |
| 48 | + | exit "${1:-0}" | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | while [[ $# -gt 0 ]]; do | |
| 52 | + | case "$1" in | |
| 53 | + | -p|--path) WP_PATH="${2:-}"; shift 2 ;; | |
| 54 | + | -o|--owner) OWNER="${2:-}"; shift 2 ;; | |
| 55 | + | -g|--group) GROUP="${2:-}"; shift 2 ;; | |
| 56 | + | --group-write) GROUP_WRITE=true; shift ;; | |
| 57 | + | --strict) STRICT=true; shift ;; | |
| 58 | + | -n|--dry-run) DRY_RUN=true; shift ;; | |
| 59 | + | -h|--help) usage 0 ;; | |
| 60 | + | *) echo "Unknown option: $1" >&2; usage 1 ;; | |
| 61 | + | esac | |
| 62 | + | done | |
| 63 | + | ||
| 64 | + | # --- Sanity checks --------------------------------------------------------- | |
| 65 | + | ||
| 66 | + | [[ -z "$WP_PATH" ]] && { echo "Error: --path is empty." >&2; usage 1; } | |
| 67 | + | WP_PATH="$(cd "$WP_PATH" 2>/dev/null && pwd)" || { echo "Error: path not found." >&2; exit 1; } | |
| 68 | + | ||
| 69 | + | if [[ "$WP_PATH" == "/" || "$WP_PATH" == "$HOME" && ! -d "$WP_PATH/wp-includes" ]]; then | |
| 70 | + | echo "Error: refusing to run on '$WP_PATH'." >&2 | |
| 71 | + | exit 1 | |
| 72 | + | fi | |
| 73 | + | ||
| 74 | + | if [[ ! -d "$WP_PATH/wp-includes" || ! -d "$WP_PATH/wp-admin" ]]; then | |
| 75 | + | echo "Error: '$WP_PATH' doesn't look like a WordPress root (no wp-includes/ or wp-admin/)." >&2 | |
| 76 | + | exit 1 | |
| 77 | + | fi | |
| 78 | + | ||
| 79 | + | # wp-config.php can live in the WP root or one level above it. | |
| 80 | + | WP_CONFIG="" | |
| 81 | + | if [[ -f "$WP_PATH/wp-config.php" ]]; then WP_CONFIG="$WP_PATH/wp-config.php" | |
| 82 | + | elif [[ -f "$WP_PATH/../wp-config.php" ]]; then WP_CONFIG="$(cd "$WP_PATH/.." && pwd)/wp-config.php" | |
| 83 | + | fi | |
| 84 | + | ||
| 85 | + | if [[ -n "$OWNER" || -n "$GROUP" ]] && [[ $EUID -ne 0 ]]; then | |
| 86 | + | echo "Error: changing ownership needs root. Re-run with sudo, or drop -o/-g." >&2 | |
| 87 | + | exit 1 | |
| 88 | + | fi | |
| 89 | + | [[ -n "$OWNER" ]] && ! id -u "$OWNER" &>/dev/null && { echo "Error: user '$OWNER' doesn't exist." >&2; exit 1; } | |
| 90 | + | [[ -n "$GROUP" ]] && ! getent group "$GROUP" &>/dev/null && { echo "Error: group '$GROUP' doesn't exist." >&2; exit 1; } | |
| 91 | + | ||
| 92 | + | run() { | |
| 93 | + | if $DRY_RUN; then echo "[dry-run] $*"; else "$@"; fi | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | echo "WordPress root : $WP_PATH" | |
| 97 | + | echo "wp-config.php : ${WP_CONFIG:-not found}" | |
| 98 | + | echo "Owner:group : ${OWNER:-(unchanged)}:${GROUP:-(unchanged)}" | |
| 99 | + | echo "Uploads writable by group: $GROUP_WRITE" | |
| 100 | + | $DRY_RUN && echo "DRY RUN — nothing will be changed." | |
| 101 | + | echo | |
| 102 | + | ||
| 103 | + | # --- Ownership ------------------------------------------------------------- | |
| 104 | + | ||
| 105 | + | if [[ -n "$OWNER" || -n "$GROUP" ]]; then | |
| 106 | + | echo "Setting ownership..." | |
| 107 | + | run chown -R "${OWNER}${GROUP:+:$GROUP}" "$WP_PATH" | |
| 108 | + | [[ -n "$WP_CONFIG" && "$WP_CONFIG" != "$WP_PATH/wp-config.php" ]] && \ | |
| 109 | + | run chown "${OWNER}${GROUP:+:$GROUP}" "$WP_CONFIG" | |
| 110 | + | fi | |
| 111 | + | ||
| 112 | + | # --- Base permissions ------------------------------------------------------ | |
| 113 | + | # -P: don't follow symlinks; chmod on symlinks is skipped by -type d / -type f. | |
| 114 | + | ||
| 115 | + | echo "Setting directories to 755..." | |
| 116 | + | run find -P "$WP_PATH" -type d -exec chmod 755 {} + | |
| 117 | + | ||
| 118 | + | echo "Setting files to 644..." | |
| 119 | + | run find -P "$WP_PATH" -type f -exec chmod 644 {} + | |
| 120 | + | ||
| 121 | + | # --- Uploads --------------------------------------------------------------- | |
| 122 | + | ||
| 123 | + | UPLOADS="$WP_PATH/wp-content/uploads" | |
| 124 | + | if $GROUP_WRITE && [[ -d "$UPLOADS" ]]; then | |
| 125 | + | echo "Making uploads group-writable (775/664)..." | |
| 126 | + | run find -P "$UPLOADS" -type d -exec chmod 775 {} + | |
| 127 | + | run find -P "$UPLOADS" -type f -exec chmod 664 {} + | |
| 128 | + | # setgid so new uploads inherit the group | |
| 129 | + | run find -P "$UPLOADS" -type d -exec chmod g+s {} + | |
| 130 | + | fi | |
| 131 | + | ||
| 132 | + | # --- Sensitive files ------------------------------------------------------- | |
| 133 | + | ||
| 134 | + | if [[ -n "$WP_CONFIG" ]]; then | |
| 135 | + | if $STRICT; then | |
| 136 | + | echo "Locking wp-config.php to 600..." | |
| 137 | + | run chmod 600 "$WP_CONFIG" | |
| 138 | + | else | |
| 139 | + | echo "Locking wp-config.php to 640..." | |
| 140 | + | run chmod 640 "$WP_CONFIG" | |
| 141 | + | fi | |
| 142 | + | fi | |
| 143 | + | ||
| 144 | + | [[ -f "$WP_PATH/.htaccess" ]] && run chmod 644 "$WP_PATH/.htaccess" | |
| 145 | + | ||
| 146 | + | # Any scripts/binaries that genuinely need +x (e.g. in vendor/bin) can be | |
| 147 | + | # re-added here, e.g.: | |
| 148 | + | # run find "$WP_PATH/wp-content" -path '*/vendor/bin/*' -type f -exec chmod 755 {} + | |
| 149 | + | ||
| 150 | + | echo | |
| 151 | + | echo "Done." | |
| 152 | + | $DRY_RUN || echo "Tip: load the site and test uploads, plugin updates and the media library." | |
| 153 | + | } | |
| 154 | + | ||
| 155 | + | main "$@" | |