See invitation jayra.mattcaninto.space.

Moderate technical difficulty, but a fun project to work on. I wanted to create a unique and personalized wedding invitation website for Jayra and myself. The website is mobile-first, ensuring that it looks great* on mobile but sacrificing some desktop aesthetics.

The project involved setting up a custom Arch Linux server on DigitalOcean, deploying a web application on it, and using Docker via lazydocker for maintenance.

PostgreSQL was used for database management and an SSH into the DigitalOcean server created a proxy connection.

This was most definitely NOT the most efficient way to deploy. Updating the website requires more than a few steps: building project, pushing to Docker Hub and involved SSHing into the server, which introduces more friction than 24 grit sandpaper just to update the website.

Further, because I wanted to centralize config files locally, I also need a local compose.yaml and its accompanying secrets file that I have to maintain and keep in sync with the one on the server. Options I think might improve workflow:

  1. CI/CD pipeline using GitHub Actions to automate the build and deployment process whenever changes are pushed to the repository.
  2. Using static hosting services since current online service providers (e.g., github or cloudflare) have great static hosting options that can be easily integrated with an online hosted git repository.

A project I made after this one, Quartz Project, is deployed on a platform that allows for direct deployment from GitHub, which is much more efficient and easier to maintain and by that I mean, less friction to update and no config files to maintain.

Tech Stack

Deployment Pipeline

  1. Build docker image locally
  2. Push to Docker Hub using private repository
  3. Pull image on server and run container

Connecting to Database for messages

  1. SSH configured for ProxyCommand allowing local port forwarding to the database on the server.
  2. Connect to database using BeeKeeper (or really even VSCode Extensions such as SQLTools) with the forwarded port.

Code Snippets

SSH Config for ProxyCommand and Local Port Forwarding

~/.ssh/config
Host 1-arch-diocean-tunnel
  User arch
  ProxyCommand /usr/bin/cloudflared access ssh --hostname ${DOMAIN_WITH_SSH_ACCESS}
  LocalForward ${LOCAL_PORT} 127.0.0.1:${REMOTE_PORT}

Docker Compose File maintained locally and pushed to server as well

compose.yaml
services:
  app:
    image: ${APP_IMAGE}
    restart: always
    ports:
      - ${APP_PORT}
    environment:
      - DATABASE_URL=postgres://matt:ml@db:${PORT}/${DB}
      - R2_ACCT_ID=${R2_ACCT_ID}
      - R2_ACCESS_KEY_ID=${R2_ACCESS_KEY_ID}
      - R2_SECRET_ACCESS_KEY=${R2_SECRET_ACCESS_KEY}
      - R2_TOKEN_VALUE=${R2_TOKEN_VALUE}
      - R2_PUBLIC_URL=${R2_PUBLIC_URL}
    depends_on:
      - db
    pull_policy: always
 
  db:
    image: postgres:17
    restart: always
    environment:
      POSTGRES_USER: ${USER}
      POSTGRES_PASSWORD: ${PASS}
      POSTGRES_DB: ${DB}
    volumes:
      - db_data:/var/lib/postgresql/data
    ports:
      - ${DB_PORT}
 
volumes:
  db_data:
    external: true
    name: winvite_db_data