# Running on Linux

This guide covers **local development** and **production** deployment of Lucas Weiss Photography on a Linux host (Ubuntu/Debian-style commands; RHEL/Fedora notes where paths differ).

The app is a **Node.js + Express** server: it serves the static site from `public/`, exposes JSON APIs, and stores **admin uploads on disk** under `public/images/<category>/` (plus `thumbs/`). Metadata lives in `server/data/photos.json`.

**Apache does not replace Node.** Apache (or another reverse proxy) sits in front of Node on your **existing** host and forwards HTTP/HTTPS traffic to the app.

---

## Prerequisites

- **Node.js** 18+ and **npm** ([NodeSource](https://github.com/nodesource/distributions) or your distro’s packages)
- For a public HTTPS site on this machine: **Apache HTTP Server** (`apache2` on Debian/Ubuntu, `httpd` on RHEL/Fedora) and **certbot** with the Apache plugin
- For a long-running process: **PM2** (`sudo npm install -g pm2`) or your own **systemd** unit

Optional:

- **Python 3** + `pip` if you use the folder watcher under `watcher/`

---

## 1. Get the code on the server

From your **Linux** machine (or after SSH):

```bash
# Example: clone or unpack the project
cd ~
git clone <YOUR_REPO_URL> lucas-weiss-photography
cd lucas-weiss-photography
```

Or copy from another machine:

```bash
rsync -avz ./lucas-weiss-photography/ user@your-server:~/lucas-weiss-photography/
```

---

## 2. Environment variables

```bash
cp .env.example .env
nano .env   # or vim, etc.
```

Set:

| Variable | Purpose |
|----------|---------|
| `JWT_SECRET` | Long random secret for admin JWTs. Generate e.g. `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` |
| `ADMIN_USERNAME` | Admin login name |
| `ADMIN_PASSWORD_HASH` | Run from project root: `node server/hashpassword.js 'yourpassword'` |
| `PORT` | Listen port (default `3000`; Apache must proxy to this) |
| `NODE_ENV` | Use `production` behind HTTPS with a real domain (affects CORS; see below) |

`.env.example` in this repo no longer lists AWS keys; gallery files are **not** uploaded to S3.

### Production CORS

With `NODE_ENV=production`, allowed browser origins are hardcoded in `server/index.js`. If your site is not `lucasweiss.com`, **update that CORS list** to your `https://` origins before going live.

---

## 3. Install dependencies and run (development)

```bash
cd ~/lucas-weiss-photography
npm install
npm start
```

Or with auto-reload:

```bash
npm run dev
```

Open `http://localhost:3000` (or `http://YOUR_HOST:3000`). Admin UI: `/admin`.

Ensure the user running Node **can write** to `public/images/` (uploads create category subfolders automatically).

---

## 4. Production: Apache reverse proxy (existing host)

Apache terminates TLS (optional) and proxies **all** requests to Node. Adjust **`yourdomain.com`**, **`www.yourdomain.com`**, certificate paths, and the backend **`PORT`** (default `3000`) to match your setup.

### 4.1 Enable required modules (Debian / Ubuntu)

```bash
sudo a2enmod proxy proxy_http headers ssl rewrite
sudo systemctl reload apache2
```

On **RHEL / Fedora / CentOS**, equivalent modules are usually loaded already in `/etc/httpd/conf.modules.d/00-proxy.conf` and `00-ssl.conf`. Ensure these exist (or uncomment `LoadModule` lines in `httpd.conf`): `proxy_module`, `proxy_http_module`, `headers_module`, `ssl_module`, `rewrite_module`.

### 4.2 Upload body limit (admin photo uploads)

The old nginx config allowed **200MB** per request. Apache uses **`LimitRequestBody`** (bytes). Example: `209715200` ≈ 200 MiB.

### 4.3 Site configuration file

Create a dedicated vhost so it coexists with other sites on the same host (name-based virtual hosting via `ServerName` / `ServerAlias`).

**Debian / Ubuntu** — create `/etc/apache2/sites-available/lucas-weiss-photography.conf`:

```apache
# HTTP → HTTPS redirect (certbot may manage this block; see §4.5)
<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com

    # Let’s Encrypt (paths match certbot defaults; change domain segment if needed)
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
    # Optional: include Mozilla/Debian ssl-params if your distro ships them, e.g.:
    # Include /etc/letsencrypt/options-ssl-apache.conf

    # Large uploads (admin drag-and-drop) — bytes; ~200 MiB
    LimitRequestBody 209715200

    # Security headers (similar idea to the repo’s nginx.conf)
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # Proxy to Node (must match PORT in .env)
    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto "https"
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/

    # Optional: long cache for typical static URL extensions (Express serves these)
    <LocationMatch "\.(jpg|jpeg|png|gif|webp|ico|svg|woff2?|css|js)(\?.*)?$">
        Header set Cache-Control "public, max-age=31536000, immutable"
    </LocationMatch>

    ErrorLog ${APACHE_LOG_DIR}/lucas-weiss-photography-error.log
    CustomLog ${APACHE_LOG_DIR}/lucas-weiss-photography-access.log combined
</VirtualHost>
```

**RHEL / Fedora** — same `<VirtualHost>` blocks, but place them in e.g. `/etc/httpd/conf.d/lucas-weiss-photography.conf` and use:

```bash
sudo systemctl reload httpd
```

Log path variables: on RHEL you may replace `${APACHE_LOG_DIR}` with `logs/` (relative to `/etc/httpd`) or `/var/log/httpd/`.

### 4.4 Enable the site and reload (Debian / Ubuntu)

```bash
sudo a2ensite lucas-weiss-photography.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
```

If `apache2ctl configtest` reports errors, fix them before reloading.

### 4.5 TLS certificates with certbot (Apache)

Point DNS at this server, then:

```bash
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com
```

Certbot can create or adjust vhosts. If it duplicates listeners, keep **one** clear `ProxyPass` to `http://127.0.0.1:3000/` and **`LimitRequestBody`** on the SSL vhost. Merge by hand if certbot’s snippet and yours conflict.

**Existing host already serving other HTTPS sites:** add only the two `<VirtualHost>` blocks (or a single `*:443` vhost) with a **unique** `ServerName`; do not change other sites’ configs unless you intend to.

### 4.6 SELinux (RHEL/CentOS/Fedora)

If proxying fails with permission errors:

```bash
sudo setsebool -P httpd_can_network_connect 1
```

---

## 5. Production: run Node with PM2

Run the app as the user that owns the project (so uploads can write under `public/images`):

```bash
cd ~/lucas-weiss-photography
pm2 start server/index.js --name lucas-weiss-photography
pm2 save
pm2 startup
# Run the command PM2 prints (often involving sudo) so the app restarts on boot
```

Node must be **running before** Apache proxies; if PM2 starts after Apache, you’ll get **502 Bad Gateway** until Node is up.

---

## 6. Static assets (fonts, hero images, logos)

Place files directly under `public/` (e.g. `public/fonts/`, `public/images/hero/`). Admin uploads land in `public/images/<category-id>/`.

With the setup above, Apache forwards everything to Express, so you usually **do not** need a separate `DocumentRoot` for this app. If you later configure Apache to serve `public/` directly for `/images`, align URLs with what `photos.json` stores.

The repo’s **`nginx.conf`** is only relevant if you choose nginx instead of Apache.

---

## 7. Optional: folder watcher on Linux

The Python watcher watches directories and POSTs new images to the admin API.

```bash
cd ~/lucas-weiss-photography/watcher
python3 -m venv .venv
source .venv/bin/activate
pip install watchdog requests
cp config.json config.local.json   # optional backup
nano config.json   # server_url (https://yourdomain.com), admin_username, admin_password, folder map
python3 watcher.py
```

To run at login or boot, add a **systemd user service** or a `@reboot` cron entry pointing at `python3` and the full path to `watcher.py`. Use a **venv** so `watchdog` and `requests` resolve reliably.

---

## Useful commands

```bash
# PM2
pm2 status
pm2 logs lucas-weiss-photography
pm2 restart lucas-weiss-photography

# Apache (Debian/Ubuntu)
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo tail -f /var/log/apache2/lucas-weiss-photography-error.log

# Apache (RHEL/Fedora)
sudo apachectl configtest   # or httpd -t
sudo systemctl reload httpd
sudo tail -f /var/log/httpd/lucas-weiss-photography-error.log

# Deploy code update (example)
cd ~/lucas-weiss-photography && git pull && npm install && pm2 restart lucas-weiss-photography
```

---

## Backup reminders

- **`server/data/photos.json`** — gallery structure and URLs.
- **`public/images/`** — uploaded full images and thumbnails.

Include both in backups if you care about recovering the site.
