Sign inSign up

omairsalman/usersconnect

By omairsalman

โ€ขUpdated 3 months ago

Server-Side Rendered Node.js/TypeScript website developed during a backend development internship.

Image
1

3.0K

omairsalman/usersconnect repository overview

โ UsersConnect

A modern self-hosted social media platform built with Node.js, Express, TypeScript, MySQL, and Redis. Features posts with optional images, comments, likes/dislikes, email verification, and a guided setup wizard.

GitHub: https://github.com/OmairSalman/UsersConnectโ 
Live Version: https://usersconnect.cloudomair.org/โ 


โ โœจ What's New in v1.1.0

  • ๐Ÿ” Consistent Cross-Site Cookies - sameSite: none now applies across all auth flows (login, registration, password reset, email verification, email change), completing the mobile support started in v1.0.4
  • ๐Ÿ›ก๏ธ Insecure-Context Guard - login, register, and password-reset pages now warn and disable submission over non-HTTPS connections instead of failing silently
  • ๐Ÿ”’ HTTPS Now Required - auth cookies are always set with Secure (see note below)
  • ๐Ÿงน Dependency & Config Cleanup - removed unused packages; logging and DB-retry behavior now honor the config system
  • ๐Ÿ›ก๏ธ Security Patches - fast-xml-builder, qs, and brace-expansion updated

โ โš ๏ธ HTTPS Is Required

As of v1.1.0, authentication cookies are always set with the Secure attribute (required by SameSite=None), so the app must be served over HTTPS for sign-in to work.

  • โœ… Standard deployments put the container behind a TLS-terminating reverse proxy (Nginx Proxy Manager, Nginx, Caddy, Traefik) โ€” these already work, no action needed.
  • โŒ Plain-HTTP deployments will have authentication rejected by the browser โ€” add HTTPS in front before upgrading.
  • ๐Ÿง‘โ€๐Ÿ’ป Local development also needs HTTPS. http://localhost is treated as secure by Chrome/Firefox (so it works), but accessing from a phone over the LAN requires real TLS (e.g. mkcert or a tunnel). See "Why HTTPS is required"โ  in the README.

โ ๐Ÿš€ Quick Start

โ Step 1: Pull the Image
docker pull omairsalman/usersconnect:latest
โ Step 2: Start with Docker Compose

Save as docker-compose.yml:

version: '3.8'

services:
  app:
    image: omairsalman/usersconnect:latest
    ports:
      - "3000:3000"
    volumes:
      - ./config.yaml:/app/config.yaml
      - ./logs:/app/logs
    environment:
      - NODE_ENV=production
      - DATABASE_HOST=mysql
      - DATABASE_USERNAME=root
      - DATABASE_PASSWORD=${DATABASE_PASSWORD}
      - DATABASE_NAME=usersconnect
      - REDIS_HOST=redis
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
      - REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
    depends_on:
      - mysql
      - redis
    restart: unless-stopped

  mysql:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD}
      MYSQL_DATABASE: usersconnect
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    restart: unless-stopped

volumes:
  mysql_data:
  redis_data:
docker-compose up -d

Generate secrets for .env:

openssl rand -base64 16  # For passwords
openssl rand -base64 32  # For JWT secrets
โ Step 3: Complete Setup Wizard
  1. Visit your instance (redirects to /setup)
  2. Create your admin account
  3. Optionally configure:
    • S3 storage for image uploads
    • SMTP for email verification
    • CORS for separate frontends
  4. Click "Complete Setup"

Done! Your instance is ready to use.

Note: Because authentication now requires HTTPS, access your instance through your HTTPS reverse proxy rather than plain http://...:3000. See the HTTPS note above.


โ ๐Ÿณ Docker Run (Alternative)

โ Basic Setup
docker run -d \
  -p 3000:3000 \
  -v $(pwd)/config.yaml:/app/config.yaml \
  -v $(pwd)/logs:/app/logs \
  -e NODE_ENV=production \
  -e DATABASE_HOST=your-mysql-host \
  -e DATABASE_USERNAME=root \
  -e DATABASE_PASSWORD=yourpassword \
  -e DATABASE_NAME=usersconnect \
  -e REDIS_HOST=your-redis-host \
  -e REDIS_PASSWORD=yourredispassword \
  -e ACCESS_TOKEN_SECRET=$(openssl rand -base64 32) \
  -e REFRESH_TOKEN_SECRET=$(openssl rand -base64 32) \
  omairsalman/usersconnect:latest
โ With S3 + SMTP

Add these environment variables:

  -e S3_ACCESS_KEY=your-aws-access-key \
  -e S3_SECRET_KEY=your-aws-secret-key \
  -e S3_BUCKET_NAME=usersconnect-media \
  -e S3_REGION=us-east-1 \
  -e SMTP_HOST=smtp.zoho.com \
  -e SMTP_PORT=465 \
  -e SMTP_SECURE=true \
  -e [email protected] \
  -e SMTP_PASSWORD=your_smtp_password \

โ ๐Ÿ”ง Environment Variables

โ Required Configuration
Environment VariableYAML EquivalentDescriptionExample
DATABASE_HOSTdatabase.hostMySQL hostmysql or localhost
DATABASE_PORTdatabase.portMySQL port (optional)3306 (default)
DATABASE_USERNAMEdatabase.usernameMySQL userroot
DATABASE_PASSWORDdatabase.passwordMySQL passwordyourpassword
DATABASE_NAMEdatabase.nameDatabase nameusersconnect
REDIS_HOSTredis.hostRedis hostredis or localhost
REDIS_PORTredis.portRedis port (optional)6379 (default)
REDIS_PASSWORDredis.passwordRedis password (optional)yourredispassword
ACCESS_TOKEN_SECRETjwt.accessTokenSecretJWT access token secretGenerate: openssl rand -base64 32
REFRESH_TOKEN_SECRETjwt.refreshTokenSecretJWT refresh token secretGenerate: openssl rand -base64 32
โ Optional: S3 Image Uploads

Image uploads are automatically enabled when these variables are set:

Environment VariableYAML EquivalentDescriptionExample
S3_ACCESS_KEYs3.accessKeyS3 access key IDAKIAIOSFODNN7EXAMPLE
S3_SECRET_KEYs3.secretKeyS3 secret access keywJalrXUtnFEMI/...
S3_BUCKET_NAMEs3.bucketNameS3 bucket nameusersconnect-media
S3_REGIONs3.regionAWS regionus-east-1
S3_ENDPOINTs3.endpointCustom endpoint (for non-AWS S3)http://minio:9000
โ Optional: SMTP Email

Email features are automatically enabled when these variables are set:

Environment VariableYAML EquivalentDescriptionExample
SMTP_HOSTsmtp.hostSMTP server hostsmtp.zoho.com
SMTP_PORTsmtp.portSMTP server port465 or 587
SMTP_SECUREsmtp.secureUse SSL/TLStrue or false
SMTP_USERsmtp.userSMTP username[email protected]
SMTP_PASSWORDsmtp.passwordSMTP passwordyour_smtp_password
โ Optional: CORS Configuration

CORS is disabled by default. Enable for separate frontend applications:

Environment VariableYAML EquivalentDescriptionExample
CORS_ENABLEDcors.enabledEnable CORStrue or false
CORS_ALLOWED_ORIGINScors.allowedOriginsAllowed origins (comma-separated)http://localhost:4200,https://app.example.com
CORS_ALLOW_CREDENTIALScors.allowCredentialsAllow credentialstrue or false
CORS_ALLOWED_METHODScors.allowedMethodsAllowed HTTP methods (comma-separated)GET,POST,PUT,DELETE
CORS_ALLOWED_HEADERScors.allowedHeadersAllowed headers (comma-separated)Content-Type,Authorization
โ Optional: Logging
Environment VariableYAML EquivalentDescriptionExample
LOG_LEVELlogging.levelWinston log levelinfo, debug, warn, error

Logging file location and rotation are configurable via logging.directory, logging.maxFileSize, and logging.maxFiles in config.yaml. A relative directory (the default, logs) resolves under the app working directory (/app/logs in the container); an absolute path is honored as-is.

Configuration Priority: Environment variables always override YAML:

Defaults โ†’ config.yaml โ†’ Environment Variables
โ Complete Configuration Examples

Option 1: config.yaml Only (All Configuration)

# config.yaml - Complete example with all options

# Required: Database
database:
  host: mysql
  port: 3306
  username: root
  password: yourpassword
  name: usersconnect

# Required: Redis
redis:
  host: redis
  port: 6379
  password: yourredispassword  # Optional

# Required: JWT
jwt:
  accessTokenSecret: your-access-token-secret-here
  refreshTokenSecret: your-refresh-token-secret-here

# Optional: S3 Image Uploads (remove if not using)
s3:
  accessKey: AKIAIOSFODNN7EXAMPLE
  secretKey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
  bucketName: usersconnect-media
  region: us-east-1
  endpoint: http://minio:9000  # Only for non-AWS S3

# Optional: SMTP Email (remove if not using)
smtp:
  host: smtp.zoho.com
  port: 465
  secure: true
  user: [email protected]
  password: your_smtp_password

# Optional: CORS (remove if not using)
cors:
  enabled: true
  allowedOrigins:
    - http://localhost:4200
    - https://app.example.com
  allowCredentials: true
  allowedMethods:
    - GET
    - POST
    - PUT
    - DELETE
  allowedHeaders:
    - Content-Type
    - Authorization

# Optional: Logging
logging:
  level: info  # debug, info, warn, error

Option 2: Environment Variables Only

environment:
  # Required
  - NODE_ENV=production
  - DATABASE_HOST=mysql
  - DATABASE_PORT=3306
  - DATABASE_USERNAME=root
  - DATABASE_PASSWORD=${DATABASE_PASSWORD}
  - DATABASE_NAME=usersconnect
  - REDIS_HOST=redis
  - REDIS_PORT=6379
  - REDIS_PASSWORD=${REDIS_PASSWORD}
  - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
  - REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
  # Optional: S3
  - S3_ACCESS_KEY=AKIA...
  - S3_SECRET_KEY=${S3_SECRET_KEY}
  - S3_BUCKET_NAME=usersconnect-media
  - S3_REGION=us-east-1
  - S3_ENDPOINT=http://minio:9000
  # Optional: SMTP
  - SMTP_HOST=smtp.zoho.com
  - SMTP_PORT=465
  - SMTP_SECURE=true
  - [email protected]
  - SMTP_PASSWORD=${SMTP_PASSWORD}
  # Optional: CORS
  - CORS_ENABLED=true
  - CORS_ALLOWED_ORIGINS=http://localhost:4200
  - CORS_ALLOW_CREDENTIALS=true
  - CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE
  - CORS_ALLOWED_HEADERS=Content-Type,Authorization
  # Optional: Logging
  - LOG_LEVEL=info

Option 3: Mixed (Secrets in ENV, Config in YAML)

# docker-compose.yml
volumes:
  - ./config.yaml:/app/config.yaml
environment:
  # Secrets only
  - DATABASE_PASSWORD=${DATABASE_PASSWORD}
  - REDIS_PASSWORD=${REDIS_PASSWORD}
  - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
  - REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
  - S3_SECRET_KEY=${S3_SECRET_KEY}
  - SMTP_PASSWORD=${SMTP_PASSWORD}
# config.yaml
database:
  host: mysql
  port: 3306
  username: root
  name: usersconnect

redis:
  host: redis
  port: 6379

s3:
  accessKey: AKIA...
  bucketName: usersconnect-media
  region: us-east-1
  endpoint: http://minio:9000

smtp:
  host: smtp.zoho.com
  port: 465
  secure: true
  user: [email protected]

cors:
  enabled: true
  allowedOrigins:
    - http://localhost:4200
    - https://app.example.com
  allowCredentials: true
  allowedMethods:
    - GET
    - POST
    - PUT
    - DELETE
  allowedHeaders:
    - Content-Type
    - Authorization

logging:
  level: info

โ ๐Ÿ–ผ๏ธ S3 Image Uploads (Optional)

โ Supported Providers

Works with any S3-compatible storage:

  • โœ… AWS S3 - Industry standard
  • โœ… MinIO - Free, self-hosted, open source
  • โœ… DigitalOcean Spaces - Simple pricing ($5/month)
  • โœ… Cloudflare R2 - No egress fees
  • โœ… Backblaze B2 - Cost-effective
โ How It Works
  • With S3 configured: Image upload enabled for posts and profile pictures
  • Without S3: Upload fields hidden, all other features work normally, Gravatar used for avatars
โ MinIO (Self-Hosted) Example

Complete docker-compose with MinIO:

version: '3.8'

services:
  app:
    image: omairsalman/usersconnect:latest
    ports:
      - "3000:3000"
    volumes:
      - ./config.yaml:/app/config.yaml
      - ./logs:/app/logs
    environment:
      - NODE_ENV=production
      - DATABASE_HOST=mysql
      - DATABASE_USERNAME=root
      - DATABASE_PASSWORD=${DATABASE_PASSWORD}
      - DATABASE_NAME=usersconnect
      - REDIS_HOST=redis
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
      - REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
      # MinIO S3
      - S3_ACCESS_KEY=minioadmin
      - S3_SECRET_KEY=minioadmin
      - S3_BUCKET_NAME=usersconnect-media
      - S3_REGION=us-east-1
      - S3_ENDPOINT=http://minio:9000
    depends_on:
      - mysql
      - redis
      - minio

  mysql:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD}
      MYSQL_DATABASE: usersconnect
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data

  minio:
    image: minio/minio:latest
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    volumes:
      - minio_data:/data
    command: server /data --console-address ":9001"

  minio-setup:
    image: minio/mc:latest
    depends_on:
      - minio
    entrypoint: >
      /bin/sh -c "
      sleep 5;
      mc alias set myminio http://minio:9000 minioadmin minioadmin;
      mc mb myminio/usersconnect-media --ignore-existing;
      mc anonymous set download myminio/usersconnect-media;
      exit 0;
      "

volumes:
  mysql_data:
  redis_data:
  minio_data:

MinIO Console: http://localhost:9001 (minioadmin/minioadmin)


โ ๐Ÿ“ง Email Features (Optional)

When SMTP is configured:

  • โœ… Email Verification - 6-digit code verification for new accounts
  • โœ… Password Reset - Secure password recovery via email
  • โœ… Email Change - Verify both old and new email addresses
  • โœ… Email Privacy - Users can show/hide email on profile

When SMTP is not configured:

  • โœ… Users can register and use the platform immediately
  • โœ… All social features work normally
  • โŒ Email verification not available
  • โŒ Password reset not available

โ ๐ŸŽฏ Core Features

  • ๐Ÿ” JWT Authentication - Secure access/refresh token pattern
  • ๐Ÿ“ Posts - Create, edit, delete with optional images
  • ๐Ÿ’ฌ Comments - Nested threaded discussions
  • ๐Ÿ‘๐Ÿ‘Ž Reactions - Like and dislike posts/comments (separate counters)
  • ๐Ÿ‘ค User Profiles - Gravatar or custom profile pictures
  • ๐Ÿ”„ Paginated Feed - Redis-cached for performance
  • ๐Ÿ›ก๏ธ Admin Dashboard - User management and moderation
  • ๐ŸŽจ Responsive Design - Mobile-first Bootstrap 5 interface

โ ๐Ÿ”’ Security Best Practices

  • โœ… HTTPS Required: Auth cookies are Secure/SameSite=None, so the app must be served over HTTPS via a reverse proxy (Nginx/Caddy/Traefik/Nginx Proxy Manager)
  • โœ… Strong Secrets: Generate with openssl rand -base64 32
  • โœ… Environment Variables: Never hardcode secrets
  • โœ… Regular Updates: Keep Docker images and dependencies updated
  • โœ… Minimal Permissions: Use least-privilege for S3 IAM users
  • โœ… Key Rotation: Rotate S3 keys every 90 days

โ ๐Ÿ“Š System Requirements

Minimum:

  • MySQL 8.0+
  • Redis 7.0+
  • 1GB RAM
  • 10GB disk space
  • HTTPS reverse proxy (required for authentication)

Recommended:

  • MySQL 8.0+
  • Redis 7.0+
  • 2GB RAM
  • 20GB disk space (for media storage)
  • S3-compatible storage for images
  • SMTP server for email features

The Docker image bundles its own Node.js runtime; a local Node.js install is only needed when building from source.


โ ๐Ÿ› Troubleshooting

โ Login Not Working / Cookies Rejected
  • Ensure the app is served over HTTPS โ€” auth cookies are Secure and browsers reject them over plain HTTP
  • Confirm your reverse proxy terminates TLS and forwards to the container
  • For local development, use HTTPS (http://localhost is treated as secure by Chrome/Firefox; LAN-IP access from a phone needs real TLS)
  • If using a separate frontend, ensure CORS allowCredentials: true and your origin is in allowedOrigins
โ Database Connection Failed
  • Ensure MySQL is running and accessible
  • Check DATABASE_HOST matches your setup
  • Wait for MySQL to fully initialize (~30 seconds)
  • Add health checks to docker-compose
โ Images Not Uploading
  • Verify all S3 environment variables are set correctly
  • Check S3 bucket exists and is accessible
  • Verify IAM permissions (PutObject, GetObject, DeleteObject)
  • Check bucket policy allows public GetObject
โ Redis Connection Failed
  • Ensure Redis is running
  • Check REDIS_HOST is correct
  • Verify REDIS_PASSWORD if set
โ Setup Wizard Not Appearing
  • Setup wizard only appears if no admin exists
  • Check database is empty or create fresh database
  • Clear browser cache and try again
โ Email Features Not Working
  • Verify all SMTP environment variables are set
  • Test SMTP credentials with email client
  • Check SMTP port (465 for SSL, 587 for TLS)
  • Verify firewall allows outbound SMTP connections

โ ๐Ÿ“š Documentation


โ ๐Ÿท๏ธ Available Tags

  • latest - Latest stable release
  • 1.1.0 - Current release
  • 1.0.4, 1.0.3, 1.0.2, 1.0.1, 1.0.0 - Previous releases

Pull a specific version:

docker pull omairsalman/usersconnect:1.1.0

โ ๐Ÿ”„ Upgrading

# Backup database first
docker exec mysql mysqldump -u root -p usersconnect > backup.sql

# Pull the new image
docker pull omairsalman/usersconnect:latest

# Recreate containers (migrations run automatically)
docker-compose down
docker-compose up -d

# Verify in logs
docker-compose logs app

No breaking changes to data or configuration. Note that v1.1.0 requires the app to be served over HTTPS for authentication โ€” see the HTTPS note above.


โ ๐Ÿ’ป Building from Source

git clone https://github.com/OmairSalman/UsersConnect.git
cd UsersConnect
npm install
npm run build
docker build -t usersconnect:custom .

โ ๐Ÿ“„ License

MIT License - See LICENSEโ 


โ ๐Ÿ‘จโ€๐Ÿ’ป Author

Omair Salman

Initially developed during summer field training at AsalTechโ , with continued development thereafter.


โ ๐ŸŒŸ Support

โญ Star on GitHub: https://github.com/OmairSalman/UsersConnectโ 
๐Ÿ’ฌ Discussions: https://github.com/OmairSalman/UsersConnect/discussionsโ 
๐Ÿ› Report Issues: https://github.com/OmairSalman/UsersConnect/issuesโ 


Latest Release: v1.1.0 ๐ŸŽ‰

Tag summary

Content type

Image

Digest

sha256:49470edecโ€ฆ

Size

112.3 MB

Last updated

3 months ago

docker pull omairsalman/usersconnect