Pathogenic review: Damn, it feels good to be a virus
The hot new roguelite twin-stick shooter lives up to the hype.
The hot new roguelite twin-stick shooter lives up to the hype.
The sunny 2002 platformer was the direct follow-up to Super Mario 64.
Today is the day the EU's Right to Repair rules come into force that will, eventually, make it much easier to fix your broken gear.
This is a submission for DEV's Summer Bug Smash: Clear the Lineup powered by Sentry . You are migrating a 50,000-message Slack workspace to Zulip. Somewhere around message 31,000 the import dies with KeyError: 'ts' . Annoying, but here is the uncomfortable part: that is the lucky outcome. The unlucky one is "ts": "NaN" , where nothing dies, nothing warns, and your company's message history quietly comes out in the wrong order. TL;DR: Zulip's Slack importer used float(message["ts"]) unguarded, both as a sort key and as date_sent . One message with a missing or malformed ts aborted the entire import; a non-finite value like "NaN" did not even raise, it silently broke the sort. My fix ( zulip/zulip#39813 ) skips such messages with a warning and requires ts to parse to a finite float via math.isfinite . The regression test fails with KeyError: 'ts' on the old code. Project Overview Zulip is an open-source team chat server (Django/Python, ~25k stars) with an unusually strict engineering culture: near-total backend test coverage, strict mypy, and a commit discipline of "each commit is a minimal coherent idea". The code I touched lives in zerver/data_import/ : the subsystem that converts exports from Slack, Microsoft Teams, and Mattermost into Zulip's format. This subsystem has one property that should shape every line in it: the input is another tool's output. Import is a long batch process over data of arbitrary quality, and the admin running the migration has no way to "fix" what Slack's export tool produced. A pipeline that dies on record 31,207 of 50,000 is strictly worse than one that skips record 31,207 with a warning. Bug Fix or Performance Improvement get_messages_iterator() in zerver/data_import/slack.py streams every message of the export, sorting each day's messages by timestamp: yield from sorted ( messages_for_one_day , key = get_timestamp_from_message ) where the sort key was simply: def get_timestamp_from_message ( message : ZerverFieldsT ) -> float : retur
ImgProxy is an open-source image-processing server — resize, convert, and transform images on the fly via URL parameters, ideal as a caching layer in front of a CDN or web app. This guide builds ImgProxy from source on Ubuntu, runs it as a systemd service behind Nginx with TLS, walks through its URL processing options, and secures it with signed URLs. Prerequisites: an Ubuntu server, a domain A record (e.g. imgproxy.example.com ), non-root sudo user. Install ImgProxy ImgProxy uses libvips for image processing; this builds it from source with Go. $ sudo add-apt-repository ppa:dhor/myway $ sudo apt update $ sudo apt install libvips-dev -y $ sudo snap install --classic --channel = latest/stable go $ git clone https://github.com/imgproxy/imgproxy.git $ cd imgproxy $ sudo CGO_LDFLAGS_ALLOW = "-s|-w" go build -o /usr/local/bin/imgproxy Create the environment config: $ sudo touch /usr/local/bin/imgproxy.env $ sudo nano /usr/local/bin/imgproxy.env IMGPROXY_BIND = :8080 IMGPROXY_NETWORK = tcp IMGPROXY_READ_TIMEOUT = 10 IMGPROXY_WRITE_TIMEOUT = 10 IMGPROXY_WORKERS = 2 IMGPROXY_REQUESTS_QUEUE_SIZE = 0 IMGPROXY_QUALITY = 100 IMGPROXY_PREFERRED_FORMATS = webp,jpeg,png,gif,avif IMGPROXY_LOG_FORMAT = "pretty" IMGPROXY_LOG_LEVEL = "INFO" IMGPROXY_WATERMARK_URL = https://example.com/watermark.png IMGPROXY_WATERMARK_OPACITY = 1 Key settings: IMGPROXY_WORKERS should be ~2× your vCPU count; IMGPROXY_REQUESTS_QUEUE_SIZE=0 means unlimited queueing; IMGPROXY_WATERMARK_URL points at whatever image you want overlaid when watermarking is enabled. Point ImgProxy at the config and test: $ export IMGPROXY_ENV_LOCAL_FILE_PATH = /usr/local/bin/imgproxy.env $ cd $ imgproxy WARNING [2024-05-28T00:40:42Z] No keys defined, so signature checking is disabled WARNING [2024-05-28T00:40:42Z] No salts defined, so signature checking is disabled INFO [2024-05-28T00:40:42Z] Starting server at :8080 Stop it with Ctrl+C once verified, then set it up as a service. Run ImgProxy as a systemd Service $ sudo useradd
A few days ago I fixed update_article , one of the tools in this repo's MCP server, because it had a nasty shape: it took a bare integer article_id , PUT whatever fields you gave it straight to the DEV.to API, and if the id was wrong or hallucinated, it would silently overwrite a live published post with nothing left behind to show it had happened. The fix added a fetch-before-write diff and a JSONL audit log: _ARTICLE_UPDATE_LOG = " logs/article_updates.jsonl " def _log_article_update ( article_id , before , fields_changed , after ): os . makedirs ( os . path . dirname ( _ARTICLE_UPDATE_LOG ), exist_ok = True ) entry = { " article_id " : article_id , " fields_changed " : sorted ( fields_changed ), " url " : after . get ( " url " )} for field in fields_changed : entry [ f " { field } _before " ] = before . get ( field ) entry [ f " { field } _after " ] = after . get ( field ) with open ( _ARTICLE_UPDATE_LOG , " a " ) as f : f . write ( json . dumps ( entry ) + " \n " ) The whole point of that function is durability. "Zero trace" was the bug; a JSONL file that records before/after state on every write was the fix. I verified the logging logic itself with an offline unit test against fake before/after states and moved on, same as the diff field. What I never checked is whether logs/article_updates.jsonl outlives the process that writes it. Checking whether the trace actually exists anywhere logs/ isn't in .gitignore — I checked, it's not there. So nothing is actively hiding it. But not-hidden isn't the same as tracked: $ git log --all --oneline -- 'logs/*' $ ls logs/ ls: cannot access 'logs/': No such file or directory Empty output from the first command, across every branch and every commit this repo has ever had (50 commits, not a shallow clone — git rev-parse --is-shallow-repository is false ). Nothing has ever touched logs/ . The directory doesn't even exist right now. Not because anything deleted it — because nothing has ever run update_article in an environment
code-server is the open-source project that runs full VS Code including extensions, integrated terminal, Git, IntelliSense — on a remote server, accessible from any browser. This guide deploys it on Ubuntu 24.04 with Docker Compose, fronted by Traefik for automatic HTTPS. Prerequisites: an Ubuntu 24.04 server (1GB RAM / 2 vCPU minimum), a domain A record (e.g. code.example.com ), Docker and Docker Compose installed. Set Up the Project $ mkdir -p ~/vscode-server/ { project,config,local,letsencrypt } $ cd ~/vscode-server project — your editable workspace config — code-server settings/extensions local — user-specific data letsencrypt — Traefik's ACME certificate storage Find your UID/GID and add yourself to the docker group: $ id $USER $ sudo usermod -aG docker $USER Write the Compose File $ nano docker-compose.yml services : code-server : image : codercom/code-server:latest container_name : code-server user : " UID:GID" # Replace with your user's UID and GID environment : - PASSWORD=SECURE_PASSWORD # Replace with a strong password - DOCKER_USER=LINUXUSER # Replace with your username volumes : - ./project:/home/coder/project - ./config:/home/coder/.config - ./local:/home/coder/.local networks : - internal restart : unless-stopped labels : - " traefik.enable=true" - " traefik.http.routers.code-server.rule=Host(`CODE.EXAMPLE.COM`)" # Replace with your domain name - " traefik.http.routers.code-server.entrypoints=websecure" - " traefik.http.routers.code-server.tls.certresolver=myresolver" - " traefik.http.services.code-server.loadbalancer.server.port=8080" traefik : image : traefik:latest container_name : traefik ports : - " 80:80" - " 443:443" volumes : - /var/run/docker.sock:/var/run/docker.sock:ro - ./letsencrypt:/letsencrypt command : - " --providers.docker=true" - " --providers.docker.exposedbydefault=false" - " --providers.docker.network=internal" - " --entrypoints.web.address=:80" - " --entrypoints.websecure.address=:443" - " --entrypoints.web.http.redirections.entr
Gradio is a Python library for wrapping any ML model in a web interface, ready to deploy and scale as an app. This guide builds a GFPGAN-powered face-restoration demo with Gradio on Ubuntu 22.04, runs it as a systemd service, and exposes it through Nginx with TLS. Prerequisites: a GPU-enabled Ubuntu 22.04 server, a domain A record (e.g. gradio.example.com ), non-root sudo access, Nginx installed. Set Up the Server 1. Install dependencies: $ pip3 install realesrgan gfpgan basicsr gradio realesrgan — background restoration gfpgan — face restoration basicsr — provides RRDBNet , the super-resolution architecture GFPGAN relies on gradio — the web interface 2. GFPGAN's pandas dependency needs jinja2 >= 3.1.2: $ pip show jinja2 Upgrade if it's older: $ pip install --upgrade jinja2 3. Create the project directory: $ sudo mkdir -p /opt/gradio-webapp/ $ sudo chown -R : $( id -gn ) /opt/gradio-webapp/ $ sudo chmod -R 775 /opt/gradio-webapp/ Build the Gradio App Uploads a face image and returns two enhanced outputs. $ cd /opt/gradio-webapp/ $ nano app.py import gradio as gr from gfpgan import GFPGANer from basicsr.archs.rrdbnet_arch import RRDBNet from realesrgan import RealESRGANer import numpy as np import cv2 import requests def enhance_image ( input_image ): arch = ' clean ' model_name = ' GFPGANv1.4 ' gfpgan_checkpoint = ' https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/GFPGANv1.4.pth ' realersgan_checkpoint = ' https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth ' rrdbnet = RRDBNet ( num_in_ch = 3 , num_out_ch = 3 , num_feat = 64 , num_block = 23 , num_grow_ch = 32 , scale = 2 ) bg_upsampler = RealESRGANer ( scale = 2 , model_path = realersgan_checkpoint , model = rrdbnet , tile = 400 , tile_pad = 10 , pre_pad = 0 , half = True ) restorer = GFPGANer ( model_path = gfpgan_checkpoint , upscale = 2 , arch = arch , channel_multiplier = 2 , bg_upsampler = bg_upsampler ) input_image = input_image . astype ( np . uint8 ) cropped_fa
Metabase is an open-source BI tool for building charts and dashboards over MySQL, PostgreSQL, MongoDB, Redshift, and more. This guide deploys Metabase on Kubernetes, loads the Sakila sample dataset into MySQL, builds a dashboard, and secures it behind Nginx Ingress with cert-manager TLS. Prerequisites: a Kubernetes cluster with kubectl / helm configured, a Linux workstation, a reachable MySQL server, and a domain name. Load the Sakila Sample Database Sakila models a DVD rental store — films, actors, inventory, rentals. $ sudo apt install zip -y $ wget https://downloads.mysql.com/docs/sakila-db.zip $ unzip sakila-db.zip Connect to your MySQL server (replace host/port/user): $ mysql -h <HOST_ENDPOINT> -P <DATABASE_PORT> -u <ADMIN_USER> -p mysql > CREATE DATABASE sakila ; mysql > SOURCE sakila - db / sakila - schema . sql ; mysql > SOURCE sakila - db / sakila - data . sql ; Deploy Metabase $ nano metabase.yaml apiVersion : apps/v1 kind : Deployment metadata : name : metabase spec : selector : matchLabels : app : metabase replicas : 1 template : metadata : labels : app : metabase spec : containers : - name : metabase image : metabase/metabase:latest ports : - containerPort : 3000 protocol : TCP --- apiVersion : v1 kind : Service metadata : name : metabase-svc spec : type : LoadBalancer selector : app : metabase ports : - name : http port : 8080 targetPort : 3000 Your cloud provider may need a provider-specific LoadBalancer annotation here (e.g. to set the listener protocol) — check its Kubernetes docs if the default doesn't work. $ kubectl apply -f metabase.yaml $ kubectl get deployments $ kubectl get services Wait for metabase-svc to get an EXTERNAL-IP (can take a few minutes), then visit http://<external-ip>:8080 to confirm the Metabase welcome page loads. Connect Metabase to the Database Let's get started → pick language. Enter your name, email, company, and a password. Select your use case. Database engine: MySQL . Set a display name, then host/port/database/user/pa
Nginx UI is an open-source web GUI for managing Nginx, single-node or clustered, with real-time stats, automatic Let's Encrypt TLS, performance monitoring, and even LLM-assisted config editing. This guide installs it on Ubuntu 24.04, puts it behind a reverse proxy with TLS, sets up ACME certificate management, and creates a virtual host through the dashboard. Prerequisites: an Ubuntu 24.04 server, non-root sudo user, a domain A record (e.g. nginx-ui.example.com ), Docker installed if you choose that install path. $ sudo apt update $ sudo apt install nginx -y Pick one of the two install methods below. Option A: Install via Script Runs Nginx UI as a system service, managing the host's Nginx directly. $ curl -O https://cloud.nginxui.com/install.sh $ sudo bash install.sh install $ nginx-ui --version $ sudo systemctl start nginx-ui $ sudo systemctl status nginx-ui Option B: Install via Docker Runs as a container — you won't be able to edit the host's Nginx configs directly through it. $ mkdir -p ~/nginx-ui-docker $ cd ~/nginx-ui-docker $ sudo mkdir -p /opt/nginx-ui/nginx $ sudo mkdir -p /opt/nginx-ui/config $ sudo mkdir -p /opt/nginx-ui/www $ nano docker-compose.yml version : ' 3.8' services : nginx-ui : image : uozi/nginx-ui:latest container_name : nginx-ui restart : always environment : - TZ=UTC volumes : - /opt/nginx-ui/nginx:/etc/nginx - /opt/nginx-ui/config:/etc/nginx-ui - /opt/nginx-ui/www:/var/www ports : - " 127.0.0.1:9000:80" networks : - nginx-ui-net networks : nginx-ui-net : driver : bridge $ sudo docker compose up -d $ sudo docker compose ps $ curl -X GET http://localhost:9000 Configure the Reverse Proxy Nginx UI listens on localhost:9000 . Put it behind a public vhost with WebSocket support (needed for live stats/terminal): $ cd /etc/nginx/sites-available $ sudo nano nginx-ui.conf map $http_upgrade $connection_upgrade { default upgrade ; '' close ; } server { listen 80 ; listen [::]:80 ; server_name nginx-ui.example.com ; location / { proxy_set_header Host $
Kubernetes makes it easy to define CPU and memory requests for our applications. But there is a problem: How do we know whether those resource requests are actually correct? If an application requests: yaml resources: requests: cpu: "1000m" memory: "1Gi" but normally consumes only a few millicores of CPU and a few megabytes of memory, we may be reserving significantly more cluster capacity than the workload actually needs. I wanted to understand how Kubernetes cost optimization platforms detect this situation, so I built a small hands-on lab using: Google Kubernetes Engine (GKE) CAST AI Kubernetes Docker FastAPI Google Artifact Registry The goal wasn't simply to install CAST AI. I wanted to observe the complete process: Deploy workload ↓ Observe resource usage ↓ Compare requests vs usage ↓ Identify over-provisioning ↓ Generate recommendation ↓ Apply rightsizing ↓ Verify from Kubernetes Architecture The lab architecture was intentionally simple. FastAPI Coffee API | v Docker Image | v Google Artifact Registry | v GKE Cluster | v Kubernetes Deployment | +----------------+ | | v v Pod #1 Pod #2 | | +-------+--------+ | v ClusterIP Service + | v CAST AI | +-------+-------+ | | v v Cost Monitoring Workload Optimization 1. Building a Small Test Application I created a very small FastAPI application for the experiment. from fastapi import FastAPI import socket import os import time app = FastAPI() @app.get("/") def home(): return { "message": "Coffee Shop API", "hostname": socket.gethostname(), "pod": os.getenv("HOSTNAME"), "time": time.time() } @app.get("/coffee") def coffee(): return { "coffee": "Cappuccino", "price": 120 } The hostname in the response was useful later because I could see which Kubernetes Pod handled each request. 2. Containerizing the API The application was packaged using Docker. FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app.py . EXPOSE 8000 CMD ["uvicorn", "app:app", "--host", "0
Ghost is an open-source publishing platform with built-in newsletters, memberships, subscriptions, ActivityPub federation, and Tinybird-powered web analytics. This guide covers two install paths on Ubuntu 24.04: Ghost-CLI for a traditional host install, and Docker Compose for a containerized deployment with analytics. Prerequisites: an Ubuntu 24.04 server, non-root sudo user, a domain A record (e.g. ghost.example.com ). Option A: Install with Ghost-CLI Install Node.js Ghost requires Node v22 LTS — check compatible versions before installing elsewhere. $ curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh $ sudo -E bash nodesource_setup.sh $ sudo apt install -y nodejs $ node -v Install and Configure MySQL $ sudo apt install -y mysql-server $ mysql --version $ sudo mysql_secure_installation Walk through the prompts: enable password validation ( y ), pick strong policy ( 2 ), remove anonymous users ( y ), restrict root to localhost ( y ), drop the test database ( y ), reload privileges ( y ). $ sudo mysql mysql > CREATE DATABASE ghost_db ; mysql > CREATE USER 'ghostuser' @ 'localhost' IDENTIFIED BY 'Your_password2!' ; mysql > GRANT ALL PRIVILEGES ON ghost_db . * TO 'ghostuser' @ 'localhost' ; mysql > FLUSH PRIVILEGES ; mysql > EXIT ; Install Nginx $ sudo apt install -y nginx $ sudo ufw allow 'Nginx Full' $ sudo systemctl status nginx Install Ghost $ sudo npm install ghost-cli@latest -g $ sudo mkdir -p /var/www/html/ghost $ sudo chown $USER : $USER /var/www/html/ghost $ sudo chmod 775 /var/www/html/ghost $ cd /var/www/html/ghost $ ghost install The installer prompts for: Blog URL : https://ghost.example.com MySQL hostname : localhost MySQL username/password/database : from the setup above Set up Nginx? : y Set up SSL? : y (installs acme.sh ) Email for SSL : your address Set up Systemd? : y Start Ghost? : y Manage the Config $ nano /var/www/html/ghost/config.production.json $ cd /var/www/html/ghost $ ghost restart Or via systemd (replace ghost-example
phpBB is an open-source forum application for building discussion communities — user registration, moderation, permissions, and multiple boards in one interface. This guide deploys phpBB on Ubuntu 22.04 with an external MySQL database, an Apache virtual host, and Let's Encrypt TLS. Prerequisites: an Ubuntu 22.04 server with the LAMP stack installed, non-root sudo user, an external MySQL database, a subdomain A record (e.g. phpbb.example.com ). Create the Database $ mysql -h your-db-host -P 3306 -u dbadmin -p mysql > CREATE DATABASE phpbbdb ; mysql > USE phpbbdb ; mysql > CREATE USER 'phpbbuser' @ 'localhost' IDENTIFIED BY 'securepassword' ; mysql > GRANT ALL ON phpbbdb . * to 'phpbbuser' @ 'localhost' ; mysql > FLUSH PRIVILEGES ; mysql > EXIT ; Install phpBB 1. Install PHP modules: $ sudo apt install php-mysql php-xml php-mbstring -y 2. Download and extract — check the releases page for the current version: $ wget -O phpbb.zip https://download.phpbb.com/pub/release/3.3/3.3.11/phpBB-3.3.11.zip $ unzip phpbb.zip $ sudo mv phpBB3 /var/www/html/phpbb 3. Set ownership and permissions: $ sudo chown -R www-data:www-data /var/www/html/phpbb $ sudo find /var/www/html/phpbb -type d -exec chmod 755 {} \; $ sudo find /var/www/html/phpbb -type f -exec chmod 644 {} \; Configure Apache $ sudo nano /etc/apache2/sites-available/phpbb.conf < VirtualHost *:80 > ServerAdmin admin@example.com DocumentRoot /var/www/html/phpbb ServerName phpbb.example.com < Directory /var/www/html/phpbb > Options FollowSymlinks AllowOverride All Require all granted </ Directory > ErrorLog ${APACHE_LOG_DIR}/phpbb_error.log CustomLog ${APACHE_LOG_DIR}/phpbb_access.log combined </ VirtualHost > $ sudo a2ensite phpbb $ sudo a2enmod rewrite $ sudo systemctl restart apache2 Secure phpBB 1. Firewall: $ sudo ufw status $ sudo ufw allow 22 && sudo ufw enable $ sudo ufw allow 80/tcp $ sudo ufw allow 443/tcp $ sudo ufw reload 2. TLS via Let's Encrypt: $ sudo apt install snapd -y $ sudo snap install --classic certbot
A Patroni cluster needs an odd number of nodes to maintain quorum — with 3 nodes, losing 1 still leaves a majority, so the cluster keeps running. This guide builds a 3-node PostgreSQL cluster on Ubuntu 24.04 with Patroni handling replication and automatic failover, etcd as the coordination store, and HAProxy load-balancing client connections — all secured with TLS. Prerequisites: three Ubuntu 24.04 servers (2 vCPU / 4GB RAM minimum) with PostgreSQL installed, non-root sudo access, and a domain with three A records: node1.example.com , node2.example.com , node3.example.com . Replace these placeholders with your actual subdomains throughout. Install Dependencies Run on all three nodes unless noted otherwise. 1. Install packages: $ sudo apt update $ sudo apt install haproxy certbot pipx -y $ sudo pip3 install --break-system-packages 'patroni[etcd3]' psycopg2-binary psycopg 2. Install etcd: $ wget https://github.com/etcd-io/etcd/releases/download/v3.6.4/etcd-v3.6.4-linux-amd64.tar.gz $ tar -xvf etcd-v3.6.4-linux-amd64.tar.gz $ sudo mv etcd-v3.6.4-linux-amd64/etcd etcd-v3.6.4-linux-amd64/etcdctl /usr/local/bin/ 3. Open firewall ports — 80 (Certbot), 2379/2380 (etcd), 5432/5433 (PostgreSQL + Patroni-managed PostgreSQL), 8008/8009 (Patroni REST API): $ sudo ufw allow 80,2379,2380,5432,5433,8008,8009/tcp $ sudo ufw reload $ sudo ufw status Configure SSL Certificates 1. Request a certificate per node (run on each node for its own subdomain): $ sudo certbot certonly --standalone -d node1.example.com -m admin@example.com --agree-tos --no-eff 2. Create a cert-prep script on each node (set HOSTNAME to that node's subdomain): $ sudo nano /usr/local/bin/prepare-ssl-certs.sh #!/bin/bash HOSTNAME = "node1.example.com" # Update for each node CERT_DIR = "/etc/letsencrypt/live/ $HOSTNAME " ARCHIVE_DIR = "/etc/letsencrypt/archive/ $HOSTNAME " getent group ssl-users > /dev/null || sudo groupadd ssl-users for user in etcd patroni haproxy postgres ; do if ! id " $user " > /dev/null 2>&1 &&
Laravel is a popular PHP framework with routing, authentication, and database management built in. This guide deploys a Laravel app behind Nginx on Ubuntu 24.04, wires it to MySQL, secures it with Let's Encrypt, and builds a small dashboard that queries live data. Prerequisites: Ubuntu 24.04 with Nginx and MySQL installed, a non-root sudo user, a domain A record (e.g. app.example.com ). Create the Database $ sudo mysql mysql > CREATE DATABASE laravel_demo ; mysql > CREATE USER 'laravel_user' @ 'localhost' IDENTIFIED WITH mysql_native_password BY 'secure_password' ; mysql > GRANT ALL ON laravel_demo . * TO 'laravel_user' @ 'localhost' ; mysql > FLUSH PRIVILEGES ; mysql > EXIT ; Seed a demo table to query later: $ mysql -u laravel_user -p mysql > USE laravel_demo ; mysql > CREATE TABLE server_stats ( id INT AUTO_INCREMENT , server_name VARCHAR ( 255 ), region VARCHAR ( 255 ), cpu_usage DECIMAL ( 5 , 2 ), memory_usage DECIMAL ( 5 , 2 ), status ENUM ( 'active' , 'maintenance' , 'offline' ), last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP , PRIMARY KEY ( id ) ); mysql > INSERT INTO server_stats ( server_name , region , cpu_usage , memory_usage , status ) VALUES ( 'app-01' , 'us-east' , 24 . 50 , 45 . 30 , 'active' ), ( 'db-01' , 'eu-west' , 12 . 75 , 78 . 20 , 'active' ), ( 'web-01' , 'ap-south' , 65 . 80 , 89 . 50 , 'active' ); mysql > EXIT ; Install Composer and PHP Extensions $ sudo apt update $ sudo apt install composer php php-curl php-fpm php-bcmath php-json php-mysql php-mbstring php-xml php-tokenizer php-zip -y $ composer --version $ php --version $ sudo systemctl restart php8.3-fpm php-fpm runs PHP as a service Nginx can talk to; php-mysql / php-mbstring / php-xml / php-tokenizer / php-zip cover Laravel's runtime requirements. Create the Laravel Project $ cd ~ $ composer create-project --prefer-dist laravel/laravel laravel-demo $ cd laravel-demo $ php artisan key:generate Edit .env : $ nano .env APP_NAME = laravel-demo APP_ENV = development APP_KEY = base64:APP
Dungeons & Dragons is no stranger to franchise crossovers, and now it's kicking off its biggest multiverse initiative to date, starting with a World of Warcraft expansion. Wizards of the Coast (WotC) has announced that D&D: World of Warcraft - a new sourcebook that brings Blizzard's Azeroth setting to the popular tabletop roleplaying game - […]
Slate's anti-truck EV is poised to deliver on all of its promises.
This is today’s edition of The Download, our weekday newsletter that provides a daily dose of what’s going on in the world of technology. Montana’s plan to become an experimental medical hub just pushed forward As of this week in Montana, biotech companies whose drugs have been through preliminary testing—sometimes in as few as 10…